• 仿美团实现地域选择(二)


    介绍

    上篇实现了PopupWindow选择地域,这篇介绍如何实现带有首字母的快速索引list,进行城市选择,我也是参考了相关博文才弄出来的,知道了原理,才发现如此简单。

    其中有个开源项目可以参考,但与本文实现的方式略有不同。

    地址:https://github.com/woozzu/IndexableListView

    美团的城市选择看起来是这样的。本例中不包含搜索,有空再模仿研究下。

    原理

    1、侧边快速索引和首字母直接在framelayout中布局的,也可以用代码动态生成。

    2、获取拼音首字写用到了pinyin4j开源库,但是这样效率低下,可以考虑数据库字段冗余拼音等方式提高效率。

    3、使用Comparator对获取首字母的列表进行了排序。

    4、按下快速索引之后,使用Listview.setSelectionFromTop进行定位。

    实现

    activity_city_list.xml布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:orientation="vertical" >
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff" >
    
            <ListView
                android:id="@+id/listView1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
            </ListView>
    
            
            <!-- 选中索引时,屏幕中间显示的大写字母 -->
            <TextView
                android:id="@+id/tv"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_gravity="center"
                android:background="#aaffffff"
                android:gravity="center"
                android:text="A"
                android:textColor="#aa000000"
                android:textSize="30sp" />
    
            <!-- 右侧快速索引列表 -->
            <LinearLayout
                android:id="@+id/layout"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_gravity="right"
                android:layout_marginBottom="3dp"
                android:layout_marginLeft="3dp"
                android:layout_marginTop="3dp"
                android:background="#d7d7d7"
                android:gravity="center"
                android:orientation="vertical" >
    
            </LinearLayout>
        </FrameLayout>
    
    </LinearLayout>

    item_city.xml布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    
        <!-- 列表中的index首字母,之后第一个首字母下的item显示,其他隐藏 -->
        <TextView
            android:id="@+id/tv_index"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#777777"
            android:paddingBottom="2dp"
            android:paddingLeft="10dp"
            android:paddingTop="2dp"
            android:text="index"
            android:textColor="#ffffff" />
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingBottom="10dp"
            android:paddingLeft="10dp"
            android:paddingTop="10dp" >
    
            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="城市" />
        </LinearLayout>
    
    </LinearLayout>

    CityListAdapter

    /**
     * @author Leestar54 
     * http://www.cnblogs.com/leestar54
     */
    package com.example.popupwindow;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class CityListAdapter extends BaseAdapter {
        private Context ctx;
        private ViewHolder holder;
        List<CityListItem> list;
        Map<String, Integer> selector;// 键值是索引表的字母,值为对应在listview中的位置
        String index[];//字母表
    
        public CityListAdapter(Context context, List<CityListItem> list, String[] index) {
            this.ctx = context;
            this.list = list;
            this.index = index;
            selector = new HashMap<String, Integer>();
            // 循环字母表,找出list中对应字母的位置
            for (int j = 0; j < index.length; j++) {
                for (int i = 0; i < list.size(); i++) {
                    // 由于已经按照字母排序过了,匹配中第一个就找下一个下标了。
                    if (list.get(i).getIndex().equals(index[j].toLowerCase())) {
                        selector.put(index[j], i);
                        break;
                    }
                }
            }
        }
    
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return list.size();
        }
    
        @Override
        public Object getItem(int arg0) {
            // TODO Auto-generated method stub
            return list.get(arg0);
        }
    
        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            try {
                if (convertView == null) {
                    holder = new ViewHolder();
                    convertView = LayoutInflater.from(ctx).inflate(R.layout.item_city, null);
                    holder.tv1 = (TextView) convertView.findViewById(R.id.tv1);
                    holder.index = (TextView) convertView.findViewById(R.id.tv_index);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 绑定数据
                CityListItem item = list.get(position);
                holder.tv1.setText(item.getName());
    
                // 显示index
                String currentStr = item.getIndex();
                // 上一项的index
                String previewStr = (position - 1) >= 0 ? list.get(position - 1).getIndex() : " ";
    
                //判断是否上一次的存在
                if (!previewStr.equals(currentStr)) {
                    holder.index.setVisibility(View.VISIBLE);
                    holder.index.setText(currentStr);// 文本显示当前滑动的字母
                } else {
                    holder.index.setVisibility(View.GONE);
                }
            } catch (OutOfMemoryError e) {
                Runtime.getRuntime().gc();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return convertView;
        }
    
        class ViewHolder {
            TextView tv1;
            TextView index;//索引字母
        }
    
        public Map<String, Integer> getSelector() {
            return selector;
        }
    
        public void setSelector(Map<String, Integer> selector) {
            this.selector = selector;
        }
    
        public String[] getIndex() {
            return index;
        }
    
        public void setIndex(String[] index) {
            this.index = index;
        }
    }

     CitiesActivity

    /**
     * @author Leestar54 
     * http://www.cnblogs.com/leestar54
     */
    package com.example.popupwindow;
    
    import java.text.Collator;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import android.graphics.Color;
    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnTouchListener;
    import android.widget.LinearLayout;
    import android.widget.LinearLayout.LayoutParams;
    import android.widget.ListView;
    import android.widget.TextView;
    
    public class CitiesActivity extends ActionBarActivity {
        LinearLayout layoutIndex;
        /** 字母索引表 */
        private String[] str_index = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q","R","S","T"
                ,"U", "V", "W", "X", "Y", "Z" };// "#",
    
        private int height;// 字体高度
        private List<CityListItem> listData;
        private ListView listView;
        private CityListAdapter adapter;
        private TextView tv_show;// 中间显示标题的文本
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            getSupportActionBar().setTitle("城市列表");
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeButtonEnabled(true);
    
            setContentView(R.layout.activity_city_list);
            layoutIndex = (LinearLayout) this.findViewById(R.id.layout);
            layoutIndex.setBackgroundColor(Color.parseColor("#00ffffff"));
    
            getData();
    
            tv_show = (TextView) findViewById(R.id.tv);
            tv_show.setVisibility(View.INVISIBLE);
    
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
            }
            return false;
        }
    
        /**
         * 获取城市列表
         */
        public void getData() {
            CityListItem ci1=new CityListItem();
            ci1.setName("北京");
            CityListItem ci2=new CityListItem();
            ci2.setName("上海");
            CityListItem ci3=new CityListItem();
            ci3.setName("广州");
            CityListItem ci4=new CityListItem();
            ci4.setName("广西");
            CityListItem ci5=new CityListItem();
            ci5.setName("长沙");
            CityListItem ci6=new CityListItem();
            ci6.setName("贵阳");
            CityListItem ci7=new CityListItem();
            ci7.setName("福建");
            
            ArrayList<CityListItem> list=new ArrayList<CityListItem>();
            list.add(ci1);
            list.add(ci1);
            list.add(ci1);
            list.add(ci1);
            list.add(ci1);
            list.add(ci1);
            list.add(ci2);list.add(ci2);list.add(ci2);list.add(ci2);list.add(ci2);list.add(ci2);
            list.add(ci3);list.add(ci3);list.add(ci3);list.add(ci3);list.add(ci3);
            list.add(ci4);list.add(ci4);list.add(ci4);list.add(ci4);list.add(ci4);
            list.add(ci5);    list.add(ci5);    list.add(ci5);    list.add(ci5);
            list.add(ci6);list.add(ci6);list.add(ci6);list.add(ci6);
            list.add(ci7);list.add(ci7);list.add(ci7);list.add(ci7);
            
            //获取首字母
            for (CityListItem cityListItem : list) {
                cityListItem.setIndex(String.valueOf(ChineseUtils.getHanyuPinyin(cityListItem.getName())
                        .charAt(0)));
            }
            //排序
            LetterComparator lc = new LetterComparator();
            Collections.sort(list, lc);
            
            listView = (ListView) findViewById(R.id.listView1);
            adapter = new CityListAdapter(CitiesActivity.this, list, str_index);
            listView.setAdapter(adapter);
    
        }
        
        @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            // 在oncreate里面执行下面的代码没反应,因为oncreate里面得到的getHeight=0
            // System.out.println("layoutIndex.getHeight()=" +
            // layoutIndex.getHeight());
            height = layoutIndex.getHeight() / str_index.length;
            getIndexView();
        }
    
        /** 绘制索引列表 */
        public void getIndexView() {
            LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, height);
            // params.setMargins(10, 5, 10, 0);
            for (int i = 0; i < str_index.length; i++) {
                final TextView tv = new TextView(this);
                tv.setLayoutParams(params);
                tv.setText(str_index[i]);
                tv.setPadding(10, 0, 10, 0);
                layoutIndex.addView(tv);
                layoutIndex.setOnTouchListener(new OnTouchListener() {
    
                    @Override
                    public boolean onTouch(View v, MotionEvent event)
    
                    {
                        float y = event.getY();
                        int index = (int) (y / height);
                        if (index > -1 && index < str_index.length) {// 防止越界
                            String key = str_index[index];
                            if (adapter.getSelector().containsKey(key)) {
                                // 获得位置
                                int pos = adapter.getSelector().get(key);
                                if (listView.getHeaderViewsCount() > 0) {// 防止ListView有标题栏,本例中没有。
                                    listView.setSelectionFromTop(pos + listView.getHeaderViewsCount(), 0);
                                } else {
                                    listView.setSelectionFromTop(pos, 0);// 滑动到第一项
                                }
                                tv_show.setVisibility(View.VISIBLE);
                                tv_show.setText(str_index[index]);
                            }
                        }
                        switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            //按下颜色
                            layoutIndex.setBackgroundColor(Color.parseColor("#aaffffff"));
                            break;
    
                        case MotionEvent.ACTION_MOVE:
    
                            break;
                        case MotionEvent.ACTION_UP:
                            //释放还原
                            layoutIndex.setBackgroundColor(Color.parseColor("#00ffffff"));
                            tv_show.setVisibility(View.INVISIBLE);
                            break;
                        }
                        return true;
                    }
                });
            }
        }
    
        private class LetterComparator implements Comparator<CityListItem> {
    
            @Override
            public int compare(CityListItem lhs, CityListItem rhs) {
                return Collator.getInstance().compare(lhs.getIndex(), rhs.getIndex());
            }
        }
    }

    最后看起来应该是这样的

    demo地址:

     链接:http://pan.baidu.com/s/1o6keEKE 密码:ssbn

     大多都是参考别人的,还有许多地方不完善呢,慢慢来吧。

    参考:

    http://blog.csdn.net/pathuang68/article/details/6692882

    http://www.cnblogs.com/Jaylong/archive/2013/04/13/android_view.html

    http://blog.csdn.net/wwj_748/article/details/17305195

    http://blog.csdn.net/xiaanming/article/details/12684155

  • 相关阅读:
    09、自学——Linux的学习进度与任务【目录文件的操作】
    08、自学——Linux的学习进度与任务【文件管理类命令—操作】
    07、自学——Linux的学习进度与任务【文件管理类命令—查看】
    06、自学——Linux的学习进度与任务【FHS】
    05、自学——Linux的学习进度与任务【shell中bash的特性】
    04、自学——Linux的学习进度与任务【时间日期管理类的命令】
    vue中computed、methods、watched比较
    vue中props组件传值
    vue中component组件使用——模块化开发和全局组件
    vue项目启动配置
  • 原文地址:https://www.cnblogs.com/leestar54/p/4237738.html
Copyright © 2020-2023  润新知