笔记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
<TextView
android:id="@+id/dialog"
android:layout_width="80.0dip"
android:layout_height="80.0dip"
android:layout_gravity="center"
android:background="@drawable/sorlistview_show_head_toast_bg"
android:gravity="center"
android:textColor="#ffffffff"
android:textSize="30.0dip"
android:visibility="invisible" />
<com.example.book_mediarecorder.SideBar
android:id="@+id/sidrbar"
android:layout_width="30.0dip"
android:layout_height="fill_parent"
android:layout_gravity="right|center" />
自定义view
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(20);
// 选中的状态
if (i == choose) {
paint.setColor(Color.parseColor("#3399ff"));
paint.setFakeBoldText(true);
// paint.setTextSize(30);
}
// 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:
//设置右侧字母列表[A,B,C,D,E....]的背景颜色
setBackgroundResource(R.drawable.sortlistview_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);
}
}
MainActivity
dialog = (TextView) findViewById(R.id.dialog); //中间显示的大字母
sideBar.setTextView(dialog);
//设置右侧触摸监听
sideBar = (SideBar) findViewById(R.id.sidrbar);
sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {
@Override
public void onTouchingLetterChanged(String s) {
//该字母首次出现的位置
int position = adapter.getPositionForSection(s.charAt(0));
Log.i("md", "position: "+position);
if(position != -1){
//根据索引更新联系人列表位置
sortListView.setSelection(position);
}
}
});
Adapter
/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
*/
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;
}
3.2 通讯录界面ListView的数据填充加载联系人的方法容易理解,排序“加载”处理
XML
<ListView
android:id="@+id/country_lvcountry"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:divider="@null" />
主要活动
sortListView = (ListView) findViewById(R.id.country_lvcountry);
sortListView.setOnItemClickListener(new 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(), Toast.LENGTH_SHORT).show();
}
});
SourceDateList = filledData(getResources().getStringArray(R.array.date));
// 根据a-z进行排序源数据
Collections.sort(SourceDateList, pinyinComparator);//使用给定的比较器对给定的列表进行排序,相等的元素不会被重新排序。
adapter = new SortAdapter(this, SourceDateList);
sortListView.setAdapter(adapter);
PinyinComparator
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());
}
}
}
SortModel
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;
}
}
SortAdapter
public class SortAdapter extends BaseAdapter implements SectionIndexer{
private List<SortModel> list = null;
private Context mContext;
public SortAdapter(Context mContext, List<SortModel> list) {
this.mContext = mContext;
this.list = list;
}
/**
* 当ListView数据发生变化时,调用此方法来更新ListView
* @param list
*/
public void updateListView(List<SortModel> list){
this.list = list;
notifyDataSetChanged();
}
public int getCount() {
return this.list.size();
}
public Object 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_sort_listview, 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();
}
//根据position获取分类的首字母的Char ascii值
int section = getSectionForPosition(position);
//如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
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;
}
/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
*/
public int getSectionForPosition(int position) {
return list.get(position).getSortLetters().charAt(0);
}
/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
*/
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;
}
/**
* 提取英文的首字母,非英文字母用#代替。
*
* @param str
* @return
*/
private String getAlpha(String str) {
String sortStr = str.trim().substring(0, 1).toUpperCase();
// 正则表达式,判断首字母是否是英文字母
if (sortStr.matches("[A-Z]")) {
return sortStr;
} else {
return "#";
}
}
@Override
public Object[] getSections() {
return null;
}
}
加载联系人的方法容易理解,排序“加载”处理
XML
<ListView
android:id="@+id/country_lvcountry"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:divider="@null" />
主要活动
sortListView = (ListView) findViewById(R.id.country_lvcountry);
sortListView.setOnItemClickListener(new 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(), Toast.LENGTH_SHORT).show();
}
});
SourceDateList = filledData(getResources().getStringArray(R.array.date));
// 根据a-z进行排序源数据
Collections.sort(SourceDateList, pinyinComparator);//使用给定的比较器对给定的列表进行排序,相等的元素不会被重新排序。
adapter = new SortAdapter(this, SourceDateList);
sortListView.setAdapter(adapter);
PinyinComparator
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());
}
}
}
SortModel
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;
}
}
SortAdapter
public class SortAdapter extends BaseAdapter implements SectionIndexer{
private List<SortModel> list = null;
private Context mContext;
public SortAdapter(Context mContext, List<SortModel> list) {
this.mContext = mContext;
this.list = list;
}
/**
* 当ListView数据发生变化时,调用此方法来更新ListView
* @param list
*/
public void updateListView(List<SortModel> list){
this.list = list;
notifyDataSetChanged();
}
public int getCount() {
return this.list.size();
}
public Object 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_sort_listview, 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();
}
//根据position获取分类的首字母的Char ascii值
int section = getSectionForPosition(position);
//如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
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;
}
/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
*/
public int getSectionForPosition(int position) {
return list.get(position).getSortLetters().charAt(0);
}
/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
*/
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;
}
/**
* 提取英文的首字母,非英文字母用#代替。
*
* @param str
* @return
*/
private String getAlpha(String str) {
String sortStr = str.trim().substring(0, 1).toUpperCase();
// 正则表达式,判断首字母是否是英文字母
if (sortStr.matches("[A-Z]")) {
return sortStr;
} else {
return "#";
}
}
@Override
public Object[] getSections() {
return null;
}
}
3.3 联系人的搜索
搜索部分难点是拿出搜索的内容,首先自定义了ClearEditText,给出了一个textchange的监听,然后进行匹配>筛选>排序>加载到联系人列表中。
XML
<com.example.book_mediarecorder.ClearEditText
android:id="@+id/filter_edit"
android:layout_marginTop="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/sorlistview_search_bar_edit_selector"
android:drawableLeft="@drawable/sorlistview_search_bar_icon_normal"
android:hint="请输入关键字"
android:singleLine="true"
android:textSize="15.0dip" />
主要活动
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) {
}
});
/**
* 根据输入框中的值来过滤数据并更新ListView
* @param filterStr
*/
private void filterData(String filterStr){
List<SortModel> filterDateList = new ArrayList<SortModel>();
if(TextUtils.isEmpty(filterStr)){
filterDateList = SourceDateList;
}else{
filterDateList.clear();
for(SortModel sortModel : SourceDateList){
String name = sortModel.getName();
if(name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())){
filterDateList.add(sortModel);
}
}
}
// 根据a-z进行排序
Collections.sort(filterDateList, pinyinComparator);
adapter.updateListView(filterDateList);
}
自定义的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() {
//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
mClearDrawable = getCompoundDrawables()[2];
if (mClearDrawable == null) {
mClearDrawable = getResources()
.getDrawable(R.drawable.sorlistview_emotionstore_progresscancelbtn);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
setClearIconVisible(false);
setOnFocusChangeListener(this); //注册一个回调,以便在该视图的焦点发生改变时调用。
addTextChangedListener(this);
}
/**
* 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
* 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和
* EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑
*/
@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);
}
/**
* 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
*/
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
setClearIconVisible(getText().length() > 0);
} else {
setClearIconVisible(false);
}
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
* @param visible
*/
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) {
}
}
附
>笔记19 | 利用MediaRecorder实现录像
>笔记18 | 利用MediaRecorder简单实现录音
>笔记17 | 复习AlertDialog(对话框)示例
>笔记16 | 解析和练习AsyncTask
>笔记15 | 归纳总结Android动态设置TextView的颜色的四种方法
END
- 笔记20 | 学习整理开源APP(BaseAnimation)程序源码“中的通讯录效果
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
- 一个Unity材质赋值内存泄露问题
- 以太坊搭建---初始化创始块
- [LeetCode]191. Number of 1 Bits
- Hibernate关系映射级别注解(一对一双向外键关联、一对一双向外键联合主键)
- vector查找数据并返回索引
- 笔记20 | 学习整理开源APP(BaseAnimation)程序源码“中的通讯录效果
- ES6之Promise
- 对图片进行等比例缩小
- C语言学习笔记(六)——文件操作
- python Flask-SQLAlchemy 连接数据库
- Easyui Datagrid 表头和表体列对照异常
- 分享一个sqlsever DBA的blog,东西挺全面
- C++ typedef struct 引起的expected unqualified-id before...错误
- 感知器算法