仿小米通讯录 右侧滑动条与带动画的悬停列表实现(二)
2017-03-19 21:40
417 查看
效果图
为了能一眼看出如何实现 看下图
上面的title就是用到了一个RecyclerView.ItemDecoration
从字面上翻译他就是一个recyclerview item 的装饰
如何使用?
自定义一个类(IndicatorDecoration )继承 RecyclerView.ItemDecoration
IndicatorDecoration extends RecyclerView.ItemDecoration
构造方法进行一些初始化 别忘了传入 Context
public IndicatorDecoration(Context ctx, List<? extends ContactsBean> data) { super(); mContext = ctx; mData = data; final TypedArray a = mContext.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); mTitleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, ctx .getResources().getDisplayMetrics()); mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, ctx .getResources().getDisplayMetrics()); //抗锯齿 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setTextSize(mTextSize); }
设置item的边框 其实就是设置个左上右下的边距 给要Draw的东西留下位置
//设置item周围边框的补偿 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); if (position == 0) { outRect.set(0, mTitleHeight, 0, 0);//左上右下 } else if (mData.get(position).index != null && mData.get(position).index != mData.get (position - 1).index) { //如果当前条目的index 也就是 拼音首字母 和上一个条目不同 则有title outRect.set(0, mTitleHeight, 0, 0); } else { outRect.set(0, 0, 0, 0); } }
开始画
RecyclerView的draw方法中会先通过super.draw()调用父类也就是View的draw方法,进而继续调用RecyclerView的OnDraw方法,ItemDecorations的onDraw方法就在此时会被调用
@Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { int left; int top; int right; int bottom; int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams childParams = (RecyclerView.LayoutParams) child .getLayoutParams(); int position = childParams.getViewLayoutPosition(); left = parent.getPaddingLeft(); top = child.getTop() - childParams.topMargin - mTitleHeight; right = parent.getWidth() - parent.getPaddingRight(); bottom = top + mTitleHeight; if (position == 0) { drawTitle(c, left, top, r 4000 ight, bottom, child, childParams, position); } else if (mData.get(position).index != null && !mData.get(position).index .equals(mData.get (position - 1).index) ) { drawTitle(c, left, top, right, bottom, child, childParams, position); } } } private void drawTitle(Canvas c, int left, int top, int right, int bottom, View child, RecyclerView.LayoutParams params, int position) { mPaint.setColor(mContext.getResources().getColor(R.color.md_blue_300)); c.drawRect(left, top, right, bottom, mPaint); mPaint.setColor(mContext.getResources().getColor(R.color.md_white_1000)); float textHeight = getTextHeight(mData.get(position).name); // 将字母绘制到 title的中间 c.drawText(mData.get(position).index, child.getPaddingLeft(), child.getTop() - params .topMargin - mTitleHeight / 2 + textHeight / 2, mPaint); }
返回文字的高
/** * @param text * @return 返回文字的高 */ private float getTextHeight(String text) { Rect rect = new Rect(); mPaint.getTextBounds(text, 0, text.length(), rect); return rect.height(); }
动画效果实现 onDrawOver在OnDraw 方法结束后调用
当处于这种临界值 child.getTop() + child.getHeight() = mTitleHeight下一步 上面的title将要上移 (注:getTop此时为负)
所以就将 canvas上移。
@Override public void onDrawOver(Canvas c, final RecyclerView parent, RecyclerView.State state) { int firstPos = ((LinearLayoutManager) parent.getLayoutManager()) .findFirstVisibleItemPosition(); View child = parent.findViewHolderForAdapterPosition(firstPos).itemView; //canvas是否移动过的 boolean flag = false; if (!mData.get(firstPos).index.equals(mData.get(firstPos + 1 ).index)) { if (child.getTop() + child.getHeight() < mTitleHeight) { //在canvas 移动前先保存他的状态 c.save(); flag = true; c.translate(0, child.getTop() + child.getHeight() - mTitleHeight); } } //mPaint.setColor(mContext.getResources().getColor(R.color.md_blue_300)); mPaint.setColor(mContext.getResources().getColor(R.color.md_amber_900)); c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getRight() - parent .getPaddingRight(), parent.getPaddingTop() + mTitleHeight, mPaint); mPaint.setColor(mContext.getResources().getColor(R.color.md_white_1000)); float textHeight = getTextHeight(mData.get(firstPos).name); // 将字母绘制到 title的中间 c.drawText(mData.get(firstPos).index, child.getPaddingLeft(), mTitleHeight - mTitleHeight / 2 + textHeight / 2, mPaint); //如果canvas 移动过 回到他保存前的状态 if(flag){ c.restore(); } }
github:https://github.com/REIGE/AddressBook
相关文章推荐
- 仿小米通讯录 右侧滑动条与带动画的悬停列表实现(一)
- react native 实现列表滑动 菜单栏悬停 (过程优化,体验更平滑)
- andoroid实现滑动上下滑动列表的时候动画隐藏其他视图
- android实现仿照QQ好友列表滑动效果
- 初学者对通讯录软件开发的整体把握与分块实现------添加列表新内容并实现界面的跳转
- Unity 滑动列表时实现平滑阻尼效果初始篇
- Unity 滑动列表时实现平滑阻尼效果修改篇
- Android进阶:实现android系统自带查看照片动画效果 类似Gallery手势滑动
- jquery实现网站导航动画滑动效果
- Tab切换动画滑动效果的一个简单实现
- 初学者对通讯录软件开发的整体把握与分块实现----显示用户列表
- 类通讯录右侧滑动的字母条
- 实现用PHP程序登录163邮箱并取得当前用户的通讯录列表
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- Android中用ViewPager实现多页面滑动切换及动画效果的实例
- ViewSwitcher实现程序列表分屏和动画效果
- ViewSwitcher实现程序列表分屏和动画效果 推荐
- (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu