您的位置:首页 > 其它

仿小米通讯录 右侧滑动条与带动画的悬停列表实现(二)

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  通讯录 动画 小米