Android中ListView字母排序,实现字母挤压效果以及右侧快速选中字母,搜索关键字功能

来源:互联网 发布:万国数据是干嘛的 编辑:程序博客网 时间:2024/05/10 20:47

Android中ListView字母排序,实现字母挤压效果以及右侧快速选中字母,搜索关键字功能

本文中阐述如何自定义EditText实现搜索框自定义的样式以及挤压字母的思路等

  • 自定义EditText
  • 相关的drawable文件
  • 主界面以及相关的适配器
  • 结果展示

定义要呈现的EditText的样式

public class ClearEditText extends EditText implements          OnFocusChangeListener, TextWatcher {     /**     * 定义删除按钮的引用     * */    private Drawable mClearDrawable;     public ClearEditText(Context context) {         this(context, null);     }     public ClearEditText(Context context, AttributeSet attrs) {        //这个构造方法很重要,不加这个很多属性不能再XML中定义        this(context, attrs, android.R.attr.editTextStyle);    }     public ClearEditText(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    private void init() {        //获取EidtTextDrawableRight,加入没有设置我们就使用自己的默认图片,getCompoundDrawables返回的是四个方向的图片信息        mClearDrawable = getCompoundDrawables()[2];        if (mClearDrawable == null) {             mClearDrawable = getResources()                     .getDrawable(R.mipmap.emotionstore_progresscancelbtn);        }        //设置图片的宽高,前两个是组件左上角在容器中的坐标 后两个是组件的宽度和高度        mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());        //默认初始化情况清空当前的图片信息        setClearIconVisible(false);        //类似于文本框里面hint文字在初始化的时候显示或者隐藏的操作,就要用到setOnFocusChangeListener,同时监听有字符出现时就显示删除按钮        setOnFocusChangeListener(this);         addTextChangedListener(this);     }     /**     * 判断是否有删除按钮     * 设置删除按钮的点击事件:制空     * */    @Override    public boolean onTouchEvent(MotionEvent event) {         if (getCompoundDrawables()[2] != null) {             if (event.getAction() == MotionEvent.ACTION_UP) {                 boolean touchable = event.getX() > (getWidth()                         - getPaddingRight() - mClearDrawable.getIntrinsicWidth())                         && (event.getX() < ((getWidth() - getPaddingRight())));                if (touchable) {                     this.setText("");                 }             }         }         return super.onTouchEvent(event);     }     /**     * 当焦点发生变化的情况设置删除按钮     * */    @Override    public void onFocusChange(View v, boolean hasFocus) {         if (hasFocus) {             setClearIconVisible(getText().length() > 0);         } else {             setClearIconVisible(false);         }     }     /**  * 设置删除按钮的显示或隐藏场景  * */    protected void setClearIconVisible(boolean visible) {        Drawable right = visible ? mClearDrawable : null;         setCompoundDrawables(getCompoundDrawables()[0],                 getCompoundDrawables()[1], right, getCompoundDrawables()[3]);     }     /**     * 判断是否有字符,如果有存在字符添加删除按钮     * */    @Override    public void onTextChanged(CharSequence s, int start, int count,             int after) {         setClearIconVisible(s.length() > 0);     }     @Override     public void beforeTextChanged(CharSequence s, int start, int count,             int after) {     }     @Override     public void afterTextChanged(Editable s) {     }     public void setShakeAnimation(){        this.setAnimation(shakeAnimation(5));    }    public static Animation shakeAnimation(int counts){        Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);        translateAnimation.setInterpolator(new CycleInterpolator(counts));        translateAnimation.setDuration(1000);        return translateAnimation;    }}

ClearEditText设置获取焦点时的正在输入的样式以及背景样式相关的drawable文件

line_vertiacl文件

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <solid android:color="@color/black"/>    <size  android:width="1dp"/></shape>

edit_background文件
stroke是外边框的边框宽度以及颜色
solid是填充的内部色彩

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <solid android:color="@color/white"/>    <stroke android:width="1dp"        android:color="@color/green_light"/>    <corners android:radius="30dp"/>    <padding        android:bottom="6dp"        android:top="6dp"        android:left="12dp"        android:right="6dp"        /></shape>

自定义SideBar实现右边的26个字母显示快捷选取目标

public class SideBar extends View {    //触摸事件    private OnTouchingLetterChangedListener onTouchingLetterChangedListener;    //26个字母    public static String[] b = { "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 choose = -1;// 选中的    private Paint paint = new Paint();    private TextView mTextDialog;    public void setTextView(TextView mTextDialog) {        this.mTextDialog = mTextDialog;    }    public SideBar(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    public SideBar(Context context, AttributeSet attrs) {        super(context, attrs);    }    public SideBar(Context context) {        super(context);    }    /**     * 重绘界面     */    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //获取焦点改变背景颜色        int height = getHeight();// 获取对应高度        int width = getWidth(); //  获取对应宽度        int singleHeight = height / b.length;// 获取每一个字母的高度        for (int i = 0; i < b.length; i++) {            //设置每一个字母的样式            paint.setColor(Color.rgb(33, 65, 98));            // paint.setColor(Color.WHITE);            paint.setTypeface(Typeface.DEFAULT_BOLD);            paint.setAntiAlias(true);            paint.setTextSize(30);            //选中状态            if (i == choose) {                paint.setColor(Color.parseColor("#3399ff"));                paint.setFakeBoldText(true);            }            // x坐标等于中间-字符串宽度一半            float xPos = width / 2 - paint.measureText(b[i]) / 2;            //高度增加递增            float yPos = singleHeight * i + singleHeight;            canvas.drawText(b[i], xPos, yPos, paint);            paint.reset();// 重置画笔        }    }    /**     * 点击的时候的状态     * */    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        final int action = event.getAction();        final float y = event.getY();// 点击Y坐标        final int oldChoose = choose;        final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;        final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.        switch (action) {        case MotionEvent.ACTION_UP:            setBackgroundDrawable(new ColorDrawable(0x00000000));            choose = -1;            invalidate();            if (mTextDialog != null) {                mTextDialog.setVisibility(View.INVISIBLE);            }            break;        default:            setBackgroundResource(R.drawable.sidebar_background);            if (oldChoose != c) {                if (c >= 0 && c < b.length) {                    if (listener != null) {                        listener.onTouchingLetterChanged(b[c]);                    }                    if (mTextDialog != null) {                        mTextDialog.setText(b[c]);                        mTextDialog.setVisibility(View.VISIBLE);                    }                    choose = c;                    invalidate();                }            }            break;        }        return true;    }    /**     *向外公开的方法     *      * @param onTouchingLetterChangedListener     */    public void setOnTouchingLetterChangedListener(            OnTouchingLetterChangedListener onTouchingLetterChangedListener) {        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;    }    /**     * 接口     *      * @author coder     *      */    public interface OnTouchingLetterChangedListener {        public void onTouchingLetterChanged(String s);    }}

主界面的布局展示

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"    android:layout_height="fill_parent"    android:orientation="vertical"    android:focusable="true"    android:focusableInTouchMode="true"    tools:context="demo.test.com.myself.sortlistview.SortActivity">    <demo.test.com.myself.sortlistview.ClearEditText        android:layout_margin="6dp"        android:textCursorDrawable="@drawable/line_vertiacl"        android:id="@+id/filter_edit"        android:layout_marginTop="5dip"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:background="@drawable/edit_background"        android:drawableLeft="@mipmap/search_bar_icon_normal"        android:hint="请输入关键字"        android:singleLine="true"        android:textSize="15.0dip" />    <FrameLayout        android:layout_width="fill_parent"        android:layout_height="fill_parent" >        <ListView            android:id="@+id/country_lvcountry"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:layout_gravity="center"            android:divider="@null" />        <!--设置就是设置顶部的字母排序-->        <LinearLayout            android:id="@+id/title_layout"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:layout_alignParentTop="true"            android:background="#E0E0E0" >            <TextView                android:id="@+id/title"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_gravity="center_horizontal"                android:textColor="#454545"                android:paddingLeft="5dip"                android:paddingTop="5dip"                android:paddingBottom="5dip"                android:text="A"/>        </LinearLayout>        <TextView            android:id="@+id/dialog"            android:layout_width="80.0dip"            android:layout_height="80.0dip"            android:layout_gravity="center"            android:background="@drawable/toast_bg"            android:gravity="center"            android:textColor="#ffffffff"            android:textSize="30.0dip"            android:visibility="invisible" />        <demo.test.com.myself.sortlistview.SideBar            android:id="@+id/sidrbar"            android:layout_width="30.0dip"            android:layout_height="fill_parent"            android:layout_gravity="right|center" />    </FrameLayout></LinearLayout>

自定义的显示的数据Bean

public class SortModel {    private String name;   //显示的数据    private String sortLetters;  //显示数据拼音的首字母    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getSortLetters() {        return sortLetters;    }    public void setSortLetters(String sortLetters) {        this.sortLetters = sortLetters;    }}

按字母大小排序比较器实现

public class PinyinComparator implements Comparator<SortModel> {    public int compare(SortModel o1, SortModel o2) {        if (o1.getSortLetters().equals("@")                || o2.getSortLetters().equals("#")) {            return -1;        } else if (o1.getSortLetters().equals("#")                || o2.getSortLetters().equals("@")) {            return 1;        } else {            return o1.getSortLetters().compareTo(o2.getSortLetters());        }    }}

最重要的一步是要中文转拼音的操作,需要在网络中下载pinyin4j-2.5.0.jar或更高版本作为依赖添加到程序中,添加后实现转拼音方法

public static String getPingYin(String inputString) {        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);        format.setVCharType(HanyuPinyinVCharType.WITH_V);        char[] input = inputString.trim().toCharArray();        String output = "";        try {            for (char curchar : input) {                if (java.lang.Character.toString(curchar).matches("[\u4e00-\u9fa5]+")) {                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(curchar, format);                    output += temp[0];                } else                    output += java.lang.Character.toString(curchar);            }        } catch (BadHanyuPinyinOutputFormatCombination e) {            e.printStackTrace();        }        return output;    }

主界面数据展示

public class SortActivity extends Activity {    private ListView sortListView;    private SideBar sideBar;    private TextView dialog;    private SortAdapter adapter;    private ClearEditText mClearEditText;    /**     * 上次第一个可见元素,用于滚动时记录标识。     */    private int lastFirstVisibleItem = -1;    private List<SortModel> SourceDateList;    /**     * 根据拼音来排列ListView里面的数据类     */    private PinyinComparator pinyinComparator;    /**     * 分组的布局     */    private LinearLayout titleLayout;    /**     * 分组上显示的字母     */    private TextView title;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_sort);        initViews();    }    private void initViews() {        titleLayout = (LinearLayout) findViewById(R.id.title_layout);        title = (TextView) findViewById(R.id.title);        pinyinComparator = new PinyinComparator();        sideBar = (SideBar) findViewById(R.id.sidrbar);        dialog = (TextView) findViewById(R.id.dialog);        sideBar.setTextView(dialog);//设置相应的字体背景样式        //设置右侧触摸监听        sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {            @Override            public void onTouchingLetterChanged(String s) {                //该字母首次出现的位置                int position = adapter.getPositionForSection(s.charAt(0));                if (position != -1) {                    sortListView.setSelection(position);                }            }        });        sortListView = (ListView) findViewById(R.id.country_lvcountry);        sortListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                //这里要利用adapter.getItem(position)来获取当前position所对应的对象                    Toast.makeText(getApplication(), ((SortModel) adapter.getItem(position)).getName()+"="+position, Toast.LENGTH_SHORT).show();            }        });        SourceDateList = getData(getResources().getStringArray(R.array.date));        // 根据a-z进行排序源数据        Collections.sort(SourceDateList, pinyinComparator);        adapter = new SortAdapter(this, SourceDateList, this);        sortListView.setAdapter(adapter);        sortListView.setOnScrollListener(new AbsListView.OnScrollListener() {            @Override            public void onScrollStateChanged(AbsListView view, int scrollState) {            }            @Override            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,                                 int totalItemCount) {//                LogUtils.i(+visibleItemCount+"=当前对呀的Item是="+firstVisibleItem);                //字母连续断层使不能置顶,例如  D (空) F使D到F阶段不存在置顶                int section;                try{                     section = adapter.getSectionForPosition(firstVisibleItem);                }catch (Exception e){                    return ;                }                int nextSecPosition = adapter.getPositionForSection(section + 1);                //解决断层置顶                for (int i = 1; i < 30; i++) {                    //26个英文字母充分循环                    if (nextSecPosition == -1) {                        //继续累加                        int data = section + 1 + i;                        nextSecPosition = adapter.getPositionForSection(data);                    } else {                        break;                    }                }                if (firstVisibleItem != lastFirstVisibleItem) {                    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) titleLayout.getLayoutParams();                    params.topMargin = 0;                    titleLayout.setLayoutParams(params);                    title.setText(String.valueOf((char) section));                }                if (nextSecPosition == firstVisibleItem + 1) {                    View childView = view.getChildAt(0);                    if (childView != null) {                        int titleHeight = titleLayout.getHeight();                        int bottom = childView.getBottom();                        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) titleLayout                                .getLayoutParams();                        if (bottom < titleHeight) {                            float pushedDistance = bottom - titleHeight;                            params.topMargin = (int) pushedDistance;                            titleLayout.setLayoutParams(params);                        } else {                            if (params.topMargin != 0) {                                params.topMargin = 0;                                titleLayout.setLayoutParams(params);                            }                        }                    }                }                lastFirstVisibleItem = firstVisibleItem;            }        });        mClearEditText = (ClearEditText) findViewById(R.id.filter_edit);        //根据输入框输入值的改变来过滤搜索        mClearEditText.addTextChangedListener(new TextWatcher() {            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {                //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表                filterData(s.toString());            }            @Override            public void beforeTextChanged(CharSequence s, int start, int count,                                          int after) {            }            @Override            public void afterTextChanged(Editable s) {            }        });    }    private List<SortModel> getData(String[] data) {        List<SortModel> listarray = new ArrayList<SortModel>();        for (int i = 0; i < data.length; i++) {            String pinyin = CharacterParser.getPingYin(data[i]);            String Fpinyin = pinyin.substring(0, 1).toUpperCase();            SortModel person = new SortModel();            person.setName(data[i]);            //person.setPinYin(pinyin);            // 正则表达式,判断首字母是否是英文字母            if (Fpinyin.matches("[A-Z]")) {                person.setSortLetters(Fpinyin);            } else {                person.setSortLetters("#");            }            listarray.add(person);        }        return listarray;    }    /**     * 根据输入框中的值来过滤数据并更新ListView     *     * @param filterStr     */    private void filterData(String filterStr) {        List<SortModel> filterDateList = new ArrayList<SortModel>();        if (TextUtils.isEmpty(filterStr)) {            filterDateList = SourceDateList;            titleLayout.setVisibility(View.VISIBLE);            title.setText("A");        } else {            titleLayout.setVisibility(View.GONE);            filterDateList.clear();            for (SortModel sortModel : SourceDateList) {                String name = sortModel.getName();                if (name.indexOf(filterStr.toString()) != -1 || CharacterParser.getPingYin(name).startsWith(filterStr.toString())) {                    filterDateList.add(sortModel);                }            }        }        // 根据a-z进行排序        Collections.sort(filterDateList, pinyinComparator);        adapter.updateListView(filterDateList);    }}

适配器adapter展示

public class SortAdapter extends BaseAdapter implements SectionIndexer{    private List<SortModel> list = null;    private Context mContext;    public SortAdapter(Context context, List<SortModel> list ) {        this.mContext = context;        this.list = list;    }    public void updateListView(List<SortModel> list){        this.list = list;        notifyDataSetChanged();    }    public int getCount() {        return this.list.size();    }    public SortModel getItem(int position) {        return list.get(position);    }    public long getItemId(int position) {        return position;    }    public View getView(final int position, View view, ViewGroup arg2) {        ViewHolder viewHolder = null;        final SortModel mContent = list.get(position);        if (view == null) {            viewHolder = new ViewHolder();            view = LayoutInflater.from(mContext).inflate(R.layout.item, null);            viewHolder.tvTitle = (TextView) view.findViewById(R.id.title);            viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);            view.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) view.getTag();        }        //// 获取首字母的assiiint section = getSectionForPosition(position);        //通过首字母的assii值来判断是否显示字母        int positionForSelection = getPositionForSection(section);        viewHolder.tvLetter.setOnClickListener(null);        if(position == getPositionForSection(section)){            viewHolder.tvLetter.setVisibility(View.VISIBLE);            viewHolder.tvLetter.setText(mContent.getSortLetters());        }else{            viewHolder.tvLetter.setVisibility(View.GONE);        }        viewHolder.tvTitle.setText(this.list.get(position).getName());        return view;    }    final static class ViewHolder {        TextView tvLetter;        TextView tvTitle;    }    public int getSectionForPosition(int position) {        return list.get(position).getSortLetters().charAt(0);    }    public int getPositionForSection(int section) {        for (int i = 0; i < getCount(); i++) {            String sortStr = list.get(i).getSortLetters();            char firstChar = sortStr.toUpperCase().charAt(0);            if (firstChar == section) {                return i;            }        }        return -1;    }    @Override    public Object[] getSections() {        return null;    }}

结果展示

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

源码下载(请记得给好评哦,有什么问题可以留言提问,作者会尽快给予解决,O(∩_∩)O谢谢)

http://download.csdn.net/detail/wyh_healer/9566682

0 0
原创粉丝点击