笔记20 | 学习整理开源APP(BaseAnimation)程序源码“中的通讯录效果

来源:互联网 发布:dota和dota2区别 知乎 编辑:程序博客网 时间:2024/06/07 00:06

1.前言

整理学习”Android动画效果集合开源APP(BaseAnimation)程序源码“中的通讯录效果。

前人栽树:duguang 博客地址:http://blog.csdn.net/duguang77

下载地址:http://download.csdn.net/download/u011112840/6910683

后人乘凉:http://blog.csdn.net/xiangyong_1521/article/details/78273838


2.实现



3.目录

  • 3.1 A-Z的字母索引

  • 3.2 联系人界面ListView的数据填充

  • 3.3 联系人的搜索

3.1 A-Z的字母索引


通过自定义一个View界面,绘制一个A-Z竖向排列的布局,通过触摸事件监听,根据触摸的区域和字母高度的计算出position,再向联系人Listview提供一个方向输出position值!

  • XML

  1. <TextView

  2.            android:id="@+id/dialog"

  3.            android:layout_width="80.0dip"

  4.            android:layout_height="80.0dip"

  5.            android:layout_gravity="center"

  6.            android:background="@drawable/sorlistview_show_head_toast_bg"

  7.            android:gravity="center"

  8.            android:textColor="#ffffffff"

  9.            android:textSize="30.0dip"

  10.            android:visibility="invisible" />

  11.        <com.example.book_mediarecorder.SideBar

  12.            android:id="@+id/sidrbar"

  13.            android:layout_width="30.0dip"

  14.            android:layout_height="fill_parent"

  15.            android:layout_gravity="right|center" />

  • 自定义view

  1. public class SideBar extends View {

  2.    // 触摸事件

  3.    private OnTouchingLetterChangedListener onTouchingLetterChangedListener;

  4.    // 26个字母

  5.    public static String[] b = { "A", "B", "C", "D", "E", "F", "G", "H", "I",

  6.            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",

  7.            "W", "X", "Y", "Z", "#" };

  8.    private int choose = -1;// 选中

  9.    private Paint paint = new Paint();

  10.    private TextView mTextDialog;

  11.    public void setTextView(TextView mTextDialog) {

  12.        this.mTextDialog = mTextDialog;

  13.    }

  14.    public SideBar(Context context, AttributeSet attrs, int defStyle) {

  15.        super(context, attrs, defStyle);

  16.    }

  17.    public SideBar(Context context, AttributeSet attrs) {

  18.        super(context, attrs);

  19.    }

  20.    public SideBar(Context context) {

  21.        super(context);

  22.    }

  23.    /**

  24.     * 重写这个方法

  25.     */

  26.    protected void onDraw(Canvas canvas) {

  27.        super.onDraw(canvas);

  28.        // 获取焦点改变背景颜色.

  29.        int height = getHeight();// 获取对应高度

  30.        int width = getWidth(); // 获取对应宽度

  31.        int singleHeight = height / b.length;// 获取每一个字母的高度

  32.        for (int i = 0; i < b.length; i++) {

  33.            paint.setColor(Color.rgb(33, 65, 98));

  34.            // paint.setColor(Color.WHITE);

  35.            paint.setTypeface(Typeface.DEFAULT_BOLD);

  36.            paint.setAntiAlias(true);

  37.            paint.setTextSize(20);

  38.            // 选中的状态

  39.            if (i == choose) {

  40.                paint.setColor(Color.parseColor("#3399ff"));

  41.                paint.setFakeBoldText(true);

  42. //                paint.setTextSize(30);

  43.            }

  44.            // x坐标等于中间-字符串宽度的一半.

  45.            float xPos = width / 2 - paint.measureText(b[i]) / 2;

  46.            float yPos = singleHeight * i + singleHeight;

  47.            canvas.drawText(b[i], xPos, yPos, paint);

  48.            paint.reset();// 重置画笔

  49.        }

  50.    }

  51.    @Override

  52.    public boolean dispatchTouchEvent(MotionEvent event) {

  53.        final int action = event.getAction();

  54.        final float y = event.getY();// 点击y坐标

  55.        final int oldChoose = choose;

  56.        final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;

  57.        final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

  58.        switch (action) {

  59.        case MotionEvent.ACTION_UP:

  60.            setBackgroundDrawable(new ColorDrawable(0x00000000));

  61.            choose = -1;//

  62.            invalidate();

  63.            if (mTextDialog != null) {

  64.                mTextDialog.setVisibility(View.INVISIBLE);

  65.            }

  66.            break;

  67.        default:

  68.            //设置右侧字母列表[A,B,C,D,E....]的背景颜色

  69.            setBackgroundResource(R.drawable.sortlistview_sidebar_background);

  70.            if (oldChoose != c) {

  71.                if (c >= 0 && c < b.length) {

  72.                    if (listener != null) {

  73.                        listener.onTouchingLetterChanged(b[c]);

  74.                    }

  75.                    if (mTextDialog != null) {

  76.                        mTextDialog.setText(b[c]);

  77.                        mTextDialog.setVisibility(View.VISIBLE);

  78.                    }

  79.                    choose = c;

  80.                    invalidate();

  81.                }

  82.            }

  83.            break;

  84.        }

  85.        return true;

  86.    }

  87.    /**

  88.     * 向外公开的方法

  89.     *

  90.     * @param onTouchingLetterChangedListener

  91.     */

  92.    public void setOnTouchingLetterChangedListener(

  93.            OnTouchingLetterChangedListener onTouchingLetterChangedListener) {

  94.        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;

  95.    }

  96.    /**

  97.     * 接口

  98.     *

  99.     * @author coder

  100.     *

  101.     */

  102.    public interface OnTouchingLetterChangedListener {

  103.        public void onTouchingLetterChanged(String s);

  104.    }

  105. }

  • MainActivity

  1. dialog = (TextView) findViewById(R.id.dialog); //中间显示的大字母

  2. sideBar.setTextView(dialog);

  3.      //设置右侧触摸监听

  4.                sideBar = (SideBar) findViewById(R.id.sidrbar);

  5.        sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

  6.            @Override

  7.            public void onTouchingLetterChanged(String s) {

  8.                //该字母首次出现的位置

  9.                int position = adapter.getPositionForSection(s.charAt(0));

  10.                Log.i("md", "position: "+position);

  11.                if(position != -1){

  12.                    //根据索引更新联系人列表位置

  13.                    sortListView.setSelection(position);

  14.                }

  15.            }

  16.        });

  • Adapter

  1. /**

  2.     * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置

  3.     */

  4.    public int getPositionForSection(int section) {

  5.        for (int i = 0; i < getCount(); i++) {

  6.            String sortStr = list.get(i).getSortLetters();

  7.            char firstChar = sortStr.toUpperCase().charAt(0);

  8.            if (firstChar == section) {

  9.                return i;

  10.            }

  11.        }

  12.        return -1;

  13.    }


3.2 通讯录界面ListView的数据填充

加载联系人的方法容易理解,排序“加载”处理

  • XML

  1. <ListView

  2.            android:id="@+id/country_lvcountry"

  3.            android:layout_width="fill_parent"

  4.            android:layout_height="fill_parent"

  5.            android:layout_gravity="center"

  6.            android:divider="@null" />

  • 主要活动

  1. sortListView = (ListView) findViewById(R.id.country_lvcountry);

  2.        sortListView.setOnItemClickListener(new OnItemClickListener() {

  3.            @Override

  4.            public void onItemClick(AdapterView<?> parent, View view,

  5.                    int position, long id) {

  6.                //这里要利用adapter.getItem(position)来获取当前position所对应的对象

  7.                Toast.makeText(getApplication(), ((SortModel)adapter.getItem(position)).getName(), Toast.LENGTH_SHORT).show();

  8.            }

  9.        });

  10.        SourceDateList = filledData(getResources().getStringArray(R.array.date));

  11.        // 根据a-z进行排序源数据

  12.        Collections.sort(SourceDateList, pinyinComparator);//使用给定的比较器对给定的列表进行排序,相等的元素不会被重新排序。

  13.        adapter = new SortAdapter(this, SourceDateList);

  14.        sortListView.setAdapter(adapter);

  • PinyinComparator

  1. public class PinyinComparator implements Comparator<SortModel> {

  2.    public int compare(SortModel o1, SortModel o2) {

  3.        if (o1.getSortLetters().equals("@")

  4.                || o2.getSortLetters().equals("#")) {

  5.            return -1;

  6.        } else if (o1.getSortLetters().equals("#")

  7.                || o2.getSortLetters().equals("@")) {

  8.            return 1;

  9.        } else {

  10.            return o1.getSortLetters().compareTo(o2.getSortLetters());

  11.        }

  12.    }

  13. }

  • SortModel

  1. public class SortModel {

  2.    private String name;   //显示的数据

  3.    private String sortLetters;  //显示数据拼音的首字母

  4.    public String getName() {

  5.        return name;

  6.    }

  7.    public void setName(String name) {

  8.        this.name = name;

  9.    }

  10.    public String getSortLetters() {

  11.        return sortLetters;

  12.    }

  13.    public void setSortLetters(String sortLetters) {

  14.        this.sortLetters = sortLetters;

  15.    }

  16. }

  • SortAdapter

  1. public class SortAdapter extends BaseAdapter implements SectionIndexer{

  2.    private List<SortModel> list = null;

  3.    private Context mContext;

  4.    public SortAdapter(Context mContext, List<SortModel> list) {

  5.        this.mContext = mContext;

  6.        this.list = list;

  7.    }

  8.    /**

  9.     * 当ListView数据发生变化时,调用此方法来更新ListView

  10.     * @param list

  11.     */

  12.    public void updateListView(List<SortModel> list){

  13.        this.list = list;

  14.        notifyDataSetChanged();

  15.    }

  16.    public int getCount() {

  17.        return this.list.size();

  18.    }

  19.    public Object getItem(int position) {

  20.        return list.get(position);

  21.    }

  22.    public long getItemId(int position) {

  23.        return position;

  24.    }

  25.    public View getView(final int position, View view, ViewGroup arg2) {

  26.        ViewHolder viewHolder = null;

  27.        final SortModel mContent = list.get(position);

  28.        if (view == null) {

  29.            viewHolder = new ViewHolder();

  30.            view = LayoutInflater.from(mContext).inflate(R.layout.item_sort_listview, null);

  31.            viewHolder.tvTitle = (TextView) view.findViewById(R.id.title);

  32.            viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);

  33.            view.setTag(viewHolder);

  34.        } else {

  35.            viewHolder = (ViewHolder) view.getTag();

  36.        }

  37.        //根据position获取分类的首字母的Char ascii值

  38.        int section = getSectionForPosition(position);

  39.        //如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现

  40.        if(position == getPositionForSection(section)){

  41.            viewHolder.tvLetter.setVisibility(View.VISIBLE);

  42.            viewHolder.tvLetter.setText(mContent.getSortLetters());

  43.        }else{

  44.            viewHolder.tvLetter.setVisibility(View.GONE); //首字母隐藏

  45.        }  

  46.        viewHolder.tvTitle.setText(this.list.get(position).getName());

  47.        return view;

  48.    }

  49.    final static class ViewHolder {

  50.        TextView tvLetter;

  51.        TextView tvTitle;

  52.    }

  53.    /**

  54.     * 根据ListView的当前位置获取分类的首字母的Char ascii值

  55.     */

  56.    public int getSectionForPosition(int position) {

  57.        return list.get(position).getSortLetters().charAt(0);

  58.    }

  59.    /**

  60.     * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置

  61.     */

  62.    public int getPositionForSection(int section) {

  63.        for (int i = 0; i < getCount(); i++) {

  64.            String sortStr = list.get(i).getSortLetters();

  65.            char firstChar = sortStr.toUpperCase().charAt(0);

  66.            if (firstChar == section) {

  67.                return i;

  68.            }

  69.        }

  70.        return -1;

  71.    }

  72.    /**

  73.     * 提取英文的首字母,非英文字母用#代替。

  74.     *

  75.     * @param str

  76.     * @return

  77.     */

  78.    private String getAlpha(String str) {

  79.        String  sortStr = str.trim().substring(0, 1).toUpperCase();

  80.        // 正则表达式,判断首字母是否是英文字母

  81.        if (sortStr.matches("[A-Z]")) {

  82.            return sortStr;

  83.        } else {

  84.            return "#";

  85.        }

  86.    }

  87.    @Override

  88.    public Object[] getSections() {

  89.        return null;

  90.    }

  91. }


3.3 联系人的搜索

搜索部分难点是拿出搜索的内容,首先自定义了ClearEditText,给出了一个textchange的监听,然后进行匹配>筛选>排序>加载到联系人列表中。

  • XML

  1. <com.example.book_mediarecorder.ClearEditText

  2.        android:id="@+id/filter_edit"

  3.        android:layout_marginTop="5dip"

  4.        android:layout_width="fill_parent"

  5.        android:layout_height="wrap_content"

  6.        android:background="@drawable/sorlistview_search_bar_edit_selector"

  7.        android:drawableLeft="@drawable/sorlistview_search_bar_icon_normal"

  8.        android:hint="请输入关键字"

  9.        android:singleLine="true"

  10.        android:textSize="15.0dip" />

  • 主要活动

  1. mClearEditText = (ClearEditText) findViewById(R.id.filter_edit);

  2.        //根据输入框输入值的改变来过滤搜索

  3.        mClearEditText.addTextChangedListener(new TextWatcher() {

  4.            @Override

  5.            public void onTextChanged(CharSequence s, int start, int before, int count) {

  6.                //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表

  7.                filterData(s.toString());

  8.            }

  9.            @Override

  10.            public void beforeTextChanged(CharSequence s, int start, int count,

  11.                    int after) {

  12.            }

  13.            @Override

  14.            public void afterTextChanged(Editable s) {

  15.            }

  16.        });

  17.         /**

  18.     * 根据输入框中的值来过滤数据并更新ListView

  19.     * @param filterStr

  20.     */

  21.    private void filterData(String filterStr){

  22.        List<SortModel> filterDateList = new ArrayList<SortModel>();

  23.        if(TextUtils.isEmpty(filterStr)){

  24.            filterDateList = SourceDateList;

  25.        }else{

  26.            filterDateList.clear();

  27.            for(SortModel sortModel : SourceDateList){

  28.                String name = sortModel.getName();

  29.                if(name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())){

  30.                    filterDateList.add(sortModel);

  31.                }

  32.            }

  33.        }

  34.        // 根据a-z进行排序

  35.        Collections.sort(filterDateList, pinyinComparator);

  36.        adapter.updateListView(filterDateList);

  37.    }

  • 自定义的EditText

  1. public class ClearEditText extends EditText implements  

  2.        OnFocusChangeListener, TextWatcher {

  3.    /**

  4.     * 删除按钮的引用

  5.     */

  6.    private Drawable mClearDrawable;

  7.    public ClearEditText(Context context) {

  8.        this(context, null);

  9.    }

  10.    public ClearEditText(Context context, AttributeSet attrs) {

  11.        //这里构造方法也很重要,不加这个很多属性不能再XML里面定义

  12.        this(context, attrs, android.R.attr.editTextStyle);

  13.    }

  14.    public ClearEditText(Context context, AttributeSet attrs, int defStyle) {

  15.        super(context, attrs, defStyle);

  16.        init();

  17.    }

  18.    private void init() {

  19.        //获取EditText的DrawableRight,假如没有设置我们就使用默认的图片

  20.        mClearDrawable = getCompoundDrawables()[2];

  21.        if (mClearDrawable == null) {

  22.            mClearDrawable = getResources()

  23.                    .getDrawable(R.drawable.sorlistview_emotionstore_progresscancelbtn);

  24.        }

  25.        mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());

  26.        setClearIconVisible(false);

  27.        setOnFocusChangeListener(this); //注册一个回调,以便在该视图的焦点发生改变时调用。

  28.        addTextChangedListener(this);

  29.    }

  30.    /**

  31.     * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件

  32.     * 当我们按下的位置 在  EditText的宽度 - 图标到控件右边的间距 - 图标的宽度  和

  33.     * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑

  34.     */

  35.    @Override

  36.    public boolean onTouchEvent(MotionEvent event) {

  37.        if (getCompoundDrawables()[2] != null) {

  38.            if (event.getAction() == MotionEvent.ACTION_UP) {

  39.                boolean touchable = event.getX() > (getWidth()

  40.                        - getPaddingRight() - mClearDrawable.getIntrinsicWidth())

  41.                        && (event.getX() < ((getWidth() - getPaddingRight())));

  42.                if (touchable) {

  43.                    this.setText("");

  44.                }

  45.            }

  46.        }

  47.        return super.onTouchEvent(event);

  48.    }

  49.    /**

  50.     * 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏

  51.     */

  52.    @Override

  53.    public void onFocusChange(View v, boolean hasFocus) {

  54.        if (hasFocus) {

  55.            setClearIconVisible(getText().length() > 0);

  56.        } else {

  57.            setClearIconVisible(false);

  58.        }

  59.    }

  60.    /**

  61.     * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去

  62.     * @param visible

  63.     */

  64.    protected void setClearIconVisible(boolean visible) {

  65.        Drawable right = visible ? mClearDrawable : null;

  66.        setCompoundDrawables(getCompoundDrawables()[0],

  67.                getCompoundDrawables()[1], right, getCompoundDrawables()[3]);

  68.    }

  69.    /**

  70.     * 当输入框里面内容发生变化的时候回调的方法

  71.     */

  72.    @Override

  73.    public void onTextChanged(CharSequence s, int start, int count,

  74.            int after) {

  75.        setClearIconVisible(s.length() > 0);

  76.    }

  77.    @Override

  78.    public void beforeTextChanged(CharSequence s, int start, int count,

  79.            int after) {    

  80.    }

  81.    @Override

  82.    public void afterTextChanged(Editable s) {

  83.    }

  84. }




>笔记19 | 利用MediaRecorder实现录像

>笔记18 | 利用MediaRecorder简单实现录音

>笔记17 | 复习AlertDialog(对话框)示例

>笔记16 | 解析和练习AsyncTask

>笔记15 | 归纳总结Android动态设置TextView的颜色的四种方法


END




阅读全文
0 0
原创粉丝点击