Android自定义滚动条——城市列表

  • 效果视频
    • 绘制滚动条
      • 区别选中与未选择文字
      • 绘制等高间距
      • 滑动事件监听
    • 解析承载城市数据的XML文件
      • 下载XML文件
      • 解析文件
    • 适配器
      • 建立适配器类
      • 适配器子项视图
        • 效果图
        • 代码
      • 适配器绑定
    • 单向绑定

效果视频

绘制滚动条

区别选中与未选择文字

private void init() {mLetterList = Arrays.asList(INDEX_STRING);mTextNormalColor = Color.parseColor("#000000");mTextSelectedColor = Color.parseColor("#ff0000");}

绘制等高间距

将一个布局高度绘制成26等份,对应26个字母

 protected void onDraw(Canvas canvas) {super.onDraw(canvas);int height = getHeight();int width = getWidth();int singleHeight = height / mLetterList.size(); // 获取每一个字母的高度for (int i = 0; i < mLetterList.size(); i++) {mPaint.setColor(mTextNormalColor);mPaint.setTypeface(Typeface.DEFAULT);mPaint.setAntiAlias(true);mPaint.setTextSize(32);// 选中的状态if (i == mChoose) {mPaint.setColor(mTextSelectedColor);mPaint.setFakeBoldText(true);}// x 坐标等于中间-字符串宽度的一半float xPos = width / 2.0f - mPaint.measureText(mLetterList.get(i)) / 2;float yPos = singleHeight * i + singleHeight / 2.0f;canvas.drawText(mLetterList.get(i), xPos, yPos, mPaint);mPaint.reset(); // 重置画笔}

滑动事件监听

 public boolean onTouchEvent(MotionEvent event) {final int action = event.getAction();final float y = event.getY(); // 点击 y 坐标// 点击 y 坐标所占总高度的比例*b数组的长度就等于点击 b 中的个数final int c = (int) (y / getHeight() * mLetterList.size());switch (action) {case MotionEvent.ACTION_UP:if (mOnTextPositionChangedListener != null) {mOnTextPositionChangedListener.onActionUp();}mChoose = -1;invalidate();break;default:if (mChoose != c) {if (c >= 0 && c < mLetterList.size()) {if (mOnTouchLetterChangedListener != null) {mOnTouchLetterChangedListener.onTouchingLetterChanged(mLetterList.get(c));}mChoose = c;invalidate();}}if (mOnTextPositionChangedListener != null && y >= 0 && y <= getHeight()) {mOnTextPositionChangedListener.onTextPositionChanged(mLetterList.get(mChoose), (int) y);}break;}return true;}

解析承载城市数据的XML文件

下载XML文件

从网上下载一个包含全部城市、城市代码、城市拼音首字母的文件,可以是xml格式亦或json格式
文件下载链接

解析文件

从xml文件中取出城市数据,按城市名称、城市代码、城市首字母三个信息为一组,实例化实体类对象,并保存到列表中

private void InitCityInfo(){AllCityList = new ArrayList<>(  );String[] cityArray = getResources().getStringArray(R.array.city);// 侧边栏的索引字母ArrayList<String> indexList = new ArrayList<>();String curGroup = "0";for (int i = 0; i < cityArray.length; i += 3) {CityInfo cityInfo = new CityInfo(cityArray[i], cityArray[i + 1], cityArray[i + 2],false, false);if (!cityInfo.getGroup().equals(curGroup)) {// 如果当前城市的 group 信息与保存的不一致, 那么就是该 group 的第一个cityInfo.setIsFirstInGroup(true);// 同时将该 group 信息添加到索引中indexList.add(cityInfo.getGroup());// 它的上一个城市就是上一个 group 的最后一个if (i > 0) {AllCityList.get(AllCityList.size() - 1).setIsLastInGroup(true);}curGroup = cityInfo.getGroup();}AllCityList.add(cityInfo);}//AllCitiesScrollBar.setIndexText(indexList);}

适配器

建立适配器类

将解析出的城市数据,添加到RecyclerView子项中

public class AllCitiesReclcyerView extends RecyclerView.Adapter<AllCitiesReclcyerView.ViewHolder> {private List<CityInfo> mCityInfo;public AllCitiesReclcyerView(List<CityInfo> mCityInfo){this.mCityInfo = mCityInfo;}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from( parent.getContext() ).inflate( R.layout.allcities_recyclerview_item,null,false );return new ViewHolder( view );}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {CityInfo cityInfo = mCityInfo.get( position );holder.CityName.setText( cityInfo.getCityName());}@Overridepublic int getItemCount() {return mCityInfo.size();}public int getPositionForSection(char section) {for (int i = 0; i < getItemCount(); i++) {String group = mCityInfo.get(i).getGroup();char firstChar = group.charAt(0);if (firstChar == section) {return i;}}return -1;}class ViewHolder extends RecyclerView.ViewHolder{private TextView CityName;public ViewHolder(@NonNull View itemView) {super( itemView );CityName = itemView.findViewById( R.id.CityName );}}
}

适配器子项视图

效果图

代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/AllCities"android:layout_width="match_parent"android:layout_height="wrap_content"/><com.example.ChooseCity.SideBarandroid:id="@+id/AllCitiesScrollBar"android:layout_width="20dp"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginTop="25dp"android:background="@drawable/sidebar_style"/>
<!--  提示文字  --><TextViewandroid:id="@+id/CityTipsText"android:layout_width="36dp"android:layout_height="36dp"android:gravity="center"android:textSize="24sp"android:textColor="#C5C2C2"android:background="@drawable/scrollbar_tipstext_style"android:layout_toLeftOf="@+id/AllCitiesScrollBar"android:visibility="invisible"/>
</RelativeLayout>

适配器绑定

 View AllCities = LayoutInflater.from( City.this).inflate( R.layout.choosecity_recyclerview1,null);AllCities_RecyclerView = AllCities.findViewById( R.id.AllCities );AllCitiesScrollBar = AllCities.findViewById( R.id.AllCitiesScrollBar );CityTipsText = AllCities.findViewById( R.id.CityTipsText );LinearLayoutManager manager1 = new LinearLayoutManager( City.this );AllCities_RecyclerView.setLayoutManager( manager1 );AllCitiesReclcyerView allCitiesReclcyerView = new AllCitiesReclcyerView( AllCityList );AllCities_RecyclerView.setAdapter( allCitiesReclcyerView );//分割线

此语句作用为:为每一个子项之间添加一个分割线

  AllCities_RecyclerView.addItemDecoration(new CityItemDecoration(AllCityList));

单向绑定

通过滑动滚动条,相应的改变RecyclerView子项位置;并对滑到的滚动条字母进行突出显示

AllCities_RecyclerView.addItemDecoration(new CityItemDecoration(AllCityList));AllCitiesScrollBar.setOnTouchLetterChangedListener( new SideBar.OnTouchingLetterChangedListener() {@Overridepublic void onTouchingLetterChanged(String s) {int position = allCitiesReclcyerView.getPositionForSection(s.charAt(0));if (position != -1) {manager1.scrollToPositionWithOffset(position, 0);}}} );AllCitiesScrollBar.setOnTextPositionChangedListener( new SideBar.OnTextPositionChangedListener() {@Overridepublic void onTextPositionChanged(String c, int y) {CityTipsText.setVisibility(View.VISIBLE);int sideBarY = AllCitiesScrollBar.getTop();int topMargin = sideBarY + y - CityTipsText.getHeight() / 2;RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) CityTipsText.getLayoutParams();lp.topMargin = topMargin;CityTipsText.setLayoutParams(lp);CityTipsText.setText(c);}@Overridepublic void onActionUp() {CityTipsText.setVisibility(View.INVISIBLE);}} );

Android自定义滚动条——城市列表相关推荐

  1. android自定义滚动条(ScrollBar)样式

    虽然很少用,但是还是有应用会有自定义ListView,GridView,ScrollView等滚动条样式,这样会使得页面更加融洽美观. 其实自定义样式很简单: 1.如果你的scrollbar是Vert ...

  2. Android 城市列表选择

    最近开发一个城市选择的功能,找了这个文章 Android 城市列表选择 结果发现它使用的拼音转换库pinyin4j有一个很严重的问题,竟然长沙chang sha识别为zhang sha,结果长沙北分在 ...

  3. android百度地图定位、城市列表选择搜索

    百度地图的集成在百度地图的开发文档中有详细的介绍:Android定位SDK  | 百度地图API SDK 本文介绍的主要功能有: kotlin语言搭建的项目 百度地图的定位 选择城市(包括省市县三级搜 ...

  4. android 城市列表数据,用RecyclerView写的城市列表

    分享一下城市列表的网格布局样式的demo,代码里面包括网格布局和竖直列表布局两种样式. 网格样式: image.png 竖直列表样式: image.png 数据来源,本地的citylist.json城 ...

  5. Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

    本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...

  6. Android城市列表,首字母排序,右侧点击字母定位

    效果图: 自动定位(百度地图)+列表选择 思路: 1.请求到的城市列表,提取首字母 2.城市列表比较混乱,先使用实体类把相同首字母的城市放到一起 3.显示城市列表 4.使用QuicLocationBa ...

  7. Android 仿拼多多可水平滚动RecyclerView,自定义滚动条滚动距离

    Android 仿拼多多可水平滚动RecyclerView,自定义滚动条滚动距离 2020年,希望大家一切平安如意,毕竟这是个出人意料的多事之秋. 一.效果图: 二.快速实现: 1.主函数代码: im ...

  8. android 自定义view滚动条,Android自定义View实现等级滑动条的实例

    Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候 ...

  9. android 滚动条自定义样式,IScroll的使用-方向键绑定自定义滚动条样式

    之前在webkit上开发一个滚动控件,需要完成的是一段文字,上下键可以滚动,且自定义滚动条.第一想法就是浏览器原生overflow:scroll,且webkit支持自定义滚动条样式: webkit自定 ...

最新文章

  1. html 怎么让tr的css覆盖td的_html表格标签
  2. LeetCode-剑指 Offer 25. 合并两个排序的链表
  3. 科大星云诗社动态20210904
  4. python2中可以使用print()函数吗_在Python2.x中使用print()(函数版本)
  5. php接收不到ios值,php设置标签后,ios收不到,安卓可以收到
  6. mysql where条件使用了or会不会扫全表
  7. K8S+KubeSphere之Helm安装
  8. PS特效:图像碎片化
  9. 隐藏在华为2019财报里的“数字密码”
  10. android bugly 符号表,bugly cocos 接入和 符号表使用
  11. 采用HTML5搭建的多个网站尝鲜试用
  12. http://channel9.msdn.com/Events/MIX
  13. Java 处理 XML 的三种主流技术及介绍
  14. 黑马程序员-python笔记-从入门到入职
  15. 无线通信设备安装工程概预算编制_浙江正规设备安装工程安装-设计安装_天霖工程...
  16. MXF Operational Pattern 1a (OP1a)
  17. HTML中这是一个一级标题,html如何设置一级标题背景
  18. 【CSS应用篇】——CSS如何实现渐变背景
  19. position sticky
  20. java-net-php-python-java作业批改系统的设计PPT计算机毕业设计程序

热门文章

  1. 一篇文章汇总Python装饰器全知识图谱(使用场景,基本用法,参数传递,闭包操作,类装饰器和AOP)
  2. C++11拉达姆lamda的使用以及注意事项
  3. 爆改平衡车-->电动滑板车
  4. PR/AE等应用程序无法正常启动0xc000007b/0xc0000005,应如何解决?
  5. Java开发网站优势
  6. 同步和异步的区别及优缺点
  7. 数据透视表如何移动位置?
  8. 为什么中国的程序员总被称为「码农」?
  9. x210:uboot和系统移植
  10. 巴塞尔协议中银行风险划分