美文网首页自定义控件高级UI
Android城市索引含定位和热门城市(悬浮块+右侧字母索引)

Android城市索引含定位和热门城市(悬浮块+右侧字母索引)

作者: 一杯酒几分愁 | 来源:发表于2019-11-07 10:42 被阅读0次

    一、首先我们想要的效果是:

    • 在城市索引的列表能够加个自定义头部;
    • 有城市索引的字母悬浮块;
    • 右侧的字母索引导航;
    • 仿ios效果的当前位置索引提示框

    我们先来看下效果:

    这里写图片描述

    下面的代码可能有点多,但是效果却很不错,请耐心往下看
    这里我是用的IndexableLayout控件做的

    如果还是有不清楚的,可以去看我的Demo:CityProject

    博客地址:点击这里

    二、如何使用IndexableLayout:

    • 需要加入第三方依赖库:
    implementation 'me.yokeyword:indexablerecyclerview:1.3.0'
    
    • 在.xml布局中:
    <me.yokeyword.indexablerv.IndexableLayout
            android:id="@+id/indexableLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            app:indexBar_selectedTextColor="@color/black"  //右侧导航选中时的颜色
            app:indexBar_textColor="@color/gray1"   //右侧导航字体颜色
            app:indexBar_layout_width="40dp"        //右侧导航的宽度
            app:indexBar_textSize="14sp"         //右侧导航的字体大小
            app:indexBar_textSpace="5dp" />
    
    • 在Activity中:
      下面注释写的很清楚了,这里我就不多做说明了
    public class CityPickerActivity extends AppCompatActivity {
        //IndexableLayout 的适配器
        private ContactAdapter mAdapter;
        //自定义头部adapter
        private BannerHeaderAdapter mBannerHeaderAdapter;
        //热门城市的数组
        private String[] city = {"东莞","深圳","广州","温州","郑州","金华","佛山","上海","苏州","杭州","长沙","中山"};
        private IndexableLayout indexableLayout;
        //热门城市的适配器
        private CYBChangeCityGridViewAdapter cybChangeCityGridViewAdapter;
        热门城市的集合
        private ArrayList<String> list;
        //返回按钮
        private ImageView pic_contact_back;
        private Intent intent;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pick_contact);
    
            initview();
            initAdapter();
            onlisten();
        }
    
        public void initAdapter(){
            mAdapter = new ContactAdapter(this);        
            indexableLayout.setAdapter(mAdapter);
            //设置字母提示框为仿os居中
            indexableLayout.setOverlayStyle_Center();
            mAdapter.setDatas(initDatas());
    //        indexableLayout.setOverlayStyle_MaterialDesign(Color.RED); 设置提示框为仿联系人气泡样式
            // 全字母排序。  排序规则设置为:每个字母都会进行比较排序;速度较慢
            indexableLayout.setCompareMode(IndexableLayout.MODE_FAST);
    //        indexableLayout.addHeaderAdapter(new SimpleHeaderAdapter<>(mAdapter, "☆",null, null));
    
    //         构造函数里3个参数,分别对应 (IndexBar的字母索引, IndexTitle, 数据源), 不想显示哪个就传null, 数据源传null时,代表add一个普通的View
    //        mMenuHeaderAdapter = new MenuHeaderAdapter("↑", null, initMenuDatas());
    //        indexableLayout.addHeaderAdapter(mMenuHeaderAdapter);
    
            // 这里BannerView只有一个Item, 添加一个长度为1的任意List作为第三个参数
            List<String> bannerList = new ArrayList<>();
            bannerList.add("");
            mBannerHeaderAdapter = new BannerHeaderAdapter("↑", null, bannerList);
            indexableLayout.addHeaderAdapter(mBannerHeaderAdapter);
        }
    
        public void initview(){
            intent = getIntent();
            pic_contact_back = (ImageView) findViewById(R.id.pic_contact_back);
            indexableLayout = (IndexableLayout) findViewById(R.id.indexableLayout);
            indexableLayout.setLayoutManager(new LinearLayoutManager(this));
        }
    
        public void onlisten(){
    
            pic_contact_back.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    finish();
                }
            });
    
            mAdapter.setOnItemContentClickListener(new IndexableAdapter.OnItemContentClickListener<UserEntity>() {
                @Override
                public void onItemClick(View v, int originalPosition, int currentPosition, UserEntity entity) {
                    if (originalPosition >= 0) {
                        intent.putExtra("info", entity.getNick());
                        setResult(RESULT_OK, intent);
                        finish();
                    } else {
                        ToastUtil.showShort(CityPickerActivity.this, "选中Header/Footer:" + entity.getNick() + "  当前位置:" + currentPosition);
                    }
                }
            });
        }
    
        /**
         * 自定义的Banner Header
         */
        class BannerHeaderAdapter extends IndexableHeaderAdapter {
            private static final int TYPE = 1;
            //这里传的参数上面注释有
            public BannerHeaderAdapter(String index, String indexTitle, List datas) {
                super(index, indexTitle, datas);
            }
    
            @Override
            public int getItemViewType() {
                return TYPE;
            }
    
            @Override
            public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {
                View view = LayoutInflater.from(CityPickerActivity.this).inflate(R.layout.item_city_header, parent, false);
                VH holder = new VH(view);
                return holder;
            }
    
            @Override
            public void onBindContentViewHolder(RecyclerView.ViewHolder holder, Object entity) {
                // 数据源为null时, 该方法不用实现
                VH vh = (VH) holder;
                list=new ArrayList<>();
                for(int i = 0; i<city.length; i++){
                    list.add(city[i]);
                }
                System.out.println("------------city"+list);
                cybChangeCityGridViewAdapter=new CYBChangeCityGridViewAdapter(CityPickerActivity.this, list);
                // 绑定adpter
                vh.head_home_change_city_gridview.setAdapter(cybChangeCityGridViewAdapter);
                //热门城市的item点击事件
                vh.head_home_change_city_gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        intent.putExtra("info", list.get(position));
                        System.out.println("aaaaaayyyyyyyyy"+list.get(position));
                        setResult(RESULT_OK, intent);
                        finish();
                    }
                });
                //设置定位城市的点击事件
                vh.item_header_city_dw.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        intent.putExtra("bendi", MeNow.city);
                        setResult(RESULT_OK, intent);
                        finish();
                    }
                });
    
            }
    
            private class VH extends RecyclerView.ViewHolder {
                GridView head_home_change_city_gridview;
                TextView item_header_city_dw;
                public VH(View itemView) {
                    super(itemView);
                    head_home_change_city_gridview =(QGridView)itemView.findViewById(R.id.item_header_city_gridview);
                    item_header_city_dw = (TextView) itemView.findViewById(R.id.item_header_city_dw);
                }
            }
        }
    
        private List<UserEntity> initDatas() {
            List<UserEntity> list = new ArrayList<>();
            // 初始化数据,R.array.provinces是城市资源,下面有贴出资源文件代码
            List<String> contactStrings = Arrays.asList(getResources().getStringArray(R.array.provinces));
            List<String> mobileStrings = Arrays.asList(getResources().getStringArray(R.array.provinces));
            for (int i = 0; i < contactStrings.size(); i++) {
                UserEntity contactEntity = new UserEntity(contactStrings.get(i), mobileStrings.get(i));
                list.add(contactEntity);
            }
            return list;
        }
    }
    

    Activity的.xml文件中:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="horizontal"
            android:background="@color/white"
            android:elevation="3dp"
            >
            <ImageView
                android:id="@+id/pic_contact_back"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:src="@drawable/back"
                android:padding="18dp"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="城市选择"
                android:layout_gravity="center_vertical"
                android:textColor="@color/black"
                android:textSize="18sp"
                />
        </LinearLayout>
    
        <me.yokeyword.indexablerv.IndexableLayout
            android:id="@+id/indexableLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            app:indexBar_selectedTextColor="@color/black"
            app:indexBar_textColor="@color/gray1"
            app:indexBar_layout_width="40dp"
            app:indexBar_textSize="14sp"
            app:indexBar_textSpace="5dp" />
    
    </LinearLayout>
    

    values目录下的R.arrays.xml城市资源文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <resources>
        <string-array name="provinces">
            <item>上海</item>
            <item>北京</item>
            <item>杭州</item>
            <item>广州</item>
            ...
        </string-array>
    </resources>
    

    BannerHeaderAdapter其实就是相当于IndexableLayout的头布局,我这里的定位城市和热门城市就是通过添加这个头部(BannerHeaderAdapter的item布局):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="定位城市"
            android:gravity="center_vertical"
            android:paddingLeft="15dp"
            android:textSize="@dimen/text_size_18"
            android:textColor="@color/black"
            />
        <TextView
            android:id="@+id/item_header_city_dw"
            android:layout_width="80dp"
            android:layout_height="35dp"
            android:textColor="@color/black"
            android:gravity="center"
            android:layout_marginLeft="15dp"
            android:background="@drawable/sylayout_shop"
            android:text="东莞"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/gray2"
            android:layout_margin="15dp"
            />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingBottom="5dp"
            android:paddingLeft="15dp"
            android:paddingRight="30dp"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:textColor="@color/black"
                android:text="热门城市"/>
            <com.wzg.biswang.util.QGridView
                android:id="@+id/item_header_city_gridview"
                android:layout_marginTop="5dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:numColumns="3"
                android:stretchMode="columnWidth"
                android:columnWidth="60dp"
                android:verticalSpacing="10dp"
                android:horizontalSpacing="15dp">
            </com.wzg.biswang.util.QGridView>
        </LinearLayout>
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/gray2"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:layout_marginTop="10dp"
            />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:textSize="18sp"
            android:textColor="@color/black"
            android:layout_marginLeft="15dp"
            android:gravity="center_vertical"
            android:text="所有城市"/>
    </LinearLayout>
    

    ContactAdapter的适配器也就是IndexableLayout的Adapter,这里必须继承IndexableAdapter<UserEntity>,你也可以直接把这段代码复制下来 :

    public class ContactAdapter extends IndexableAdapter<UserEntity> {
        private LayoutInflater mInflater;
    
        public ContactAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
        }
    
    //设置悬浮块的layout
        @Override
        public RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) {
            View view = mInflater.inflate(R.layout.item_index_contact, parent, false);
            return new IndexVH(view);
        }
    //设置悬浮块下面的layout
        @Override
        public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {
            View view = mInflater.inflate(R.layout.item_contact, parent, false);
            return new ContentVH(view);
        }
    
    //设置悬浮块的数据
        @Override
        public void onBindTitleViewHolder(RecyclerView.ViewHolder holder, String indexTitle) {
            IndexVH vh = (IndexVH) holder;
            vh.tv.setText(indexTitle);
        }
    
    //设置悬浮块下面的数据
        @Override
        public void onBindContentViewHolder(RecyclerView.ViewHolder holder, UserEntity entity) {
            ContentVH vh = (ContentVH) holder;
            vh.tvName.setText(entity.getNick());
            vh.tvMobile.setText(entity.getMobile());
        }
    
        private class IndexVH extends RecyclerView.ViewHolder {
            TextView tv;
    
            public IndexVH(View itemView) {
                super(itemView);
                tv = (TextView) itemView.findViewById(R.id.tv_index);
            }
        }
    
        private class ContentVH extends RecyclerView.ViewHolder {
            TextView tvName, tvMobile;
    
            public ContentVH(View itemView) {
                super(itemView);
                tvName = (TextView) itemView.findViewById(R.id.tv_name);
                tvMobile = (TextView) itemView.findViewById(R.id.tv_mobile);
            }
        }
    }
    
    

    悬浮块的xml文件:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        
        <TextView
            android:id="@+id/tv_index"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#f9f9f9"
            android:paddingBottom="8dp"
            android:paddingLeft="24dp"
            android:paddingTop="8dp"
            android:textColor="@color/gray"
            android:text="A"
            android:textStyle="bold"
            android:textSize="14sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="0.8dp"
            android:background="#f0f0f0" />
    </FrameLayout>
    

    悬浮块下面的xml文件也就是item布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="5dp"
        android:background="?attr/selectableItemBackground"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:paddingTop="5dp">
    
        <ImageView
            android:visibility="gone"
            android:id="@+id/img_avatar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="16dp"
            android:src="@drawable/bsw_gray" />
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/img_avatar"
            tools:text="张三"
            android:textColor="#373737"
            android:textSize="16sp" />
    
        <TextView
            android:visibility="gone"
            android:id="@+id/tv_mobile"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_name"
            android:layout_marginTop="12dp"
            android:layout_toRightOf="@id/img_avatar"
            tools:text="18712345678"
            android:textColor="#969696" />
    
    </RelativeLayout>
    

    热门城市的GridView,普通的Adapter类我就不用多作解释了相信大家都能看懂:

    public class CYBChangeCityGridViewAdapter extends BaseAdapter{
        private List<String> list;
        private Context context;
        private LayoutInflater inflater;
    
        public CYBChangeCityGridViewAdapter(Context context,List<String> list){
            this.context=context;
            this.list=list;
            inflater=LayoutInflater.from(context);
        }
    
        @Override public int getCount() {
            return list.size();
        }
    
        @Override public Object getItem(int position) {
            return list.get(position);
        }
    
        @Override public long getItemId(int position) {
            return position;
        }
    
        @Override public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder=null;
            if(convertView==null){
                convertView=inflater.inflate(R.layout.item_gridview_cyb_change_city,null);
                viewHolder=new ViewHolder(convertView);
                convertView.setTag(viewHolder);
            }else {
                viewHolder=(ViewHolder)convertView.getTag();
            }
            viewHolder.item_gridview_cyb_change_city_tv.setText(list.get(position));
            return convertView;
        }
    
        class ViewHolder{
            private TextView item_gridview_cyb_change_city_tv;
            public ViewHolder(View view){
                item_gridview_cyb_change_city_tv=(TextView)view.findViewById(R.id.item_gridview_cyb_change_city_tv);
            }
        }
    }
    

    热门城市GridView的item布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:descendantFocusability="blocksDescendants"
                  android:layout_width="match_parent"
                  android:layout_height="40dp">
    <TextView
        android:id="@+id/item_gridview_cyb_change_city_tv"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@drawable/sylayout_shop"
        android:gravity="center"
        android:paddingTop="2dp"
        android:paddingBottom="2dp"
        android:textSize="13dp"
        android:layout_marginTop="5dp"
        android:text="广州"/>
    </RelativeLayout>
    

    好了,到此就结束了,赶紧去试试把!

    相关文章

      网友评论

        本文标题:Android城市索引含定位和热门城市(悬浮块+右侧字母索引)

        本文链接:https://www.haomeiwen.com/subject/lipmbctx.html