Android自定义头部悬浮,快速索引ListView
2015-09-22 13:20
417 查看
现在的App的ListView大部分都有分组头部和快速滑动索引,而且分组头部还有挤压的效果,看起来比较炫,于是就在各路大神的博客里找思路,果然发现了几种比较好的实现思路。其中夏神的关于列表快速索引是最好的,我个人认为,git上也有类似的效果但好多是重写ListView实现的,导致可扩展性变得不是很好,夏神是通过自定义View和SectionIndex实现此效果的。而头部分组挤压动画则是郭神的思路最好。通过添加OnScrollListener实现,也没有修改到ListView.
现在:我主要将两位大神的代码合并,调整优化部分代码,顺便改几个小bug。
思路上面基本说清楚了,下面看主要代码实现:
1.快速索引的实现:
代码基本copy的大神的,对一些代码的位置做了优化。主要是onDraw()让其只负责绘制相关。
2.头部挤压动画实现:
为ListView添加OnScrollListener,监听ListView的滑动。。。
夏神博客地址:/article/1645788.html
郭神博客地址:/article/1562154.html
Demo下载
现在:我主要将两位大神的代码合并,调整优化部分代码,顺便改几个小bug。
思路上面基本说清楚了,下面看主要代码实现:
1.快速索引的实现:
/** * @description 依附于列表的索引View * @author rzq * @date 2015年9月19日 */ public class SideBar extends View { /** * 要绘制的内容 */ private static String[] biao = { "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 Context mContext; private Paint mPaint; /** * View的宽高 */ private int mWidth, mHeight; /** * 单个表的高度 */ private int mSingleHeight; private int choose = -1; /** * */ private boolean isDown; private OnTouchingLetterListener mChangedListener; public SideBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SideBar(Context context) { this(context, null, 0); } public SideBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; init(); } private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setTypeface(Typeface.DEFAULT_BOLD); mPaint.setTextSize(20); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getWidth(); mHeight = getHeight(); mSingleHeight = mHeight / biao.length; } /** * onDraw()尽量值负责与绘制相关的东西 */ @Override protected void onDraw(Canvas canvas) { setBackgroundDrawable(isDown ? new ColorDrawable(0x99C60000) : new ColorDrawable(0x00000000)); for (int i = 0; i < biao.length; i++) { mPaint.setColor(i == choose ? Color.parseColor("#3399ff") : Color.rgb(33, 65, 98)); float xPos = (mWidth - mPaint.measureText(biao[i])) / 2; float yPos = mSingleHeight * i + mSingleHeight; canvas.drawText(biao[i], xPos, yPos, mPaint); } } @Override public boolean onTouchEvent(MotionEvent event) { final int oldChoose = choose; float y = event.getY(); int c = (int) (y / mHeight * biao.length); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: isDown = true; if (oldChoose != c) { if (c >= 0 && c < biao.length) { if (mChangedListener != null) { mChangedListener.onTouchingletterChanged(biao[c]); } choose = c; invalidate(); } } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: isDown = false; choose = -1; invalidate(); break; } // 将点击事件吃掉 return true; } public void setOnTouchingLetterChangedListener(OnTouchingLetterListener onTouchingLetterListener) { this.mChangedListener = onTouchingLetterListener; } public interface OnTouchingLetterListener { public void onTouchingletterChanged(String s); } } package view; import com.example.sortlistview.R; import com.example.sortlistview.SortModel; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.SectionIndexer; import android.widget.TextView; import java.util.List; /** * @description 实现了SectionIndexer的可快速滑动Adapter * @author rzq * @date 2015年9月19日 */ 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; } @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(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; final SortModel mContent = list.get(position); if (convertView == null) { viewHolder = new ViewHolder(); convertView = LayoutInflater.from(mContext).inflate(R.layout.item, null); viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.title); viewHolder.tvLetter = (TextView) convertView.findViewById(R.id.catalog); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } int section = getSectionForPosition(position); 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 convertView; } @Override public Object[] getSections() { return null; } @Override public int getPositionForSection(int sectionIndex) { for (int i = 0; i < getCount(); i++) { String sortStr = list.get(i).getSortLetters(); char firstChar = sortStr.toUpperCase().charAt(0); if (firstChar == sectionIndex) { return i; } } return -1; } @Override public int getSectionForPosition(int position) { return list.get(position).getSortLetters().charAt(0); } final static class ViewHolder { TextView tvLetter; TextView tvTitle; } }
代码基本copy的大神的,对一些代码的位置做了优化。主要是onDraw()让其只负责绘制相关。
2.头部挤压动画实现:
sortListView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } /** * 滑动结束时调用 */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { /** * 获取firstVisibleItem所在section */ int section = adapter.getSectionForPosition(firstVisibleItem); /** * 获取下一item所在section */ int nextSection = adapter.getSectionForPosition(firstVisibleItem + 1); /** * 获取下一item所在section的position */ int nextSecPosition = adapter.getPositionForSection(nextSection); /** * 显示firstVisibleItem所在分组的头部 */ if (firstVisibleItem != lastFirstVisibleItem) { MarginLayoutParams params = (MarginLayoutParams) titleLayout.getLayoutParams(); params.topMargin = 0; titleLayout.setLayoutParams(params); if (String.valueOf((char) section) != null) { 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(); MarginLayoutParams params = (MarginLayoutParams) titleLayout.getLayoutParams(); /** * 产生了碰撞,上移titleLayout */ 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; } });
为ListView添加OnScrollListener,监听ListView的滑动。。。
夏神博客地址:/article/1645788.html
郭神博客地址:/article/1562154.html
Demo下载
相关文章推荐
- Android线程池的使用
- Android消息处理机制--Handler 超详细通俗的解读
- Android学习记录:Paint,Canvas和Bitmap
- 使用RadioButton 和RadioGroup
- Android进程与线程
- 5个最佳Android测试框架
- Android SoundPool使用模板
- Android4.4.2配置修改记录
- onActivityResult无故被调用
- Android中home键和back键区别实例分析
- Android 自定义View 实现垂直滑动页
- Android判断服务是否运行及定位问题实例分析
- Android Studio 中 添加作者 时间 之类的 注释
- android R 文件消失
- android权限大全
- Android Studio整合.SO到APK
- Android加薪利器---handle异步下载图片
- Android背景渐变色(shape,gradient)
- Android 搜索 把软键盘上的回车键改为搜索
- 先锋军Android注射技术《三》