Android第二次作业:RecyclerView的设计

1.实验环境:

Windows系统,Android Studio

2.界面分析:

 

3.界面的代码实现:

3.1分隔线的实现

每个联系人与联系人之间有着一条分隔线分隔开来

核心代码如下:

/**
 * 设置屏幕的方向
 * @param orientation    LinearLayout布局是垂直还是水平
 */
public void setOrientation(int orientation){
    if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){
        throw new IllegalArgumentException("invalid orientation");
    }
    mOrientation = orientation;
}

/**
 * 用于绘画分隔线
 * @param c   画布
 * @param parent   recyclerview组件
 * @param state
 */
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    if (mOrientation == HORIZONTAL_LIST){
        drawVerticalLine(c, parent, state);
    }else {
        drawHorizontalLine(c, parent, state);
    }
}
/**
 * 画横线, 这里的parent其实是显示在屏幕显示的这部分
 * @param c   画布
 * @param parent     recyclerview组件
 * @param state
 */
public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
    int left = parent.getPaddingLeft();
    int right = parent.getWidth() - parent.getPaddingRight();
    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++){
        final View child = parent.getChildAt(i);

        //获得child的布局信息
        final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
        final int top = child.getBottom() + params.bottomMargin;
        final int bottom = top + mDivider.getIntrinsicHeight();
        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
        //Log.d("wnw", left + " " + top + " "+right+"   "+bottom+" "+i);
    }
}
/**
 * 由于Divider也有长宽高,每一个Item需要向下或者向右偏移
 * @param outRect   用于设置分隔线的坐标信息
 * @param view
 * @param parent   recyclerview组件
 * @param state
 */
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    if(mOrientation == HORIZONTAL_LIST){
        //画横线,就是往下偏移一个分割线的高度
        outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
    }else {
        //画竖线,就是往右偏移一个分割线的宽度
        outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
    }

    super.getItemOffsets(outRect, view, parent, state);
    if (users == null || users.size() == 0) {
        return;
    }

    int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
    if (position > users.size() - 1 || position < 0) {
        return;
    }
    // 第一个分类不需要显示分类章节
    if (position > 0 && !TextUtils.equals(users.get(position).getFirstChar(), users.get(position - 1).getFirstChar())) {
        outRect.set(0, mDecorationHeight, 0, 0);
    }
}

3.2stickyHeader效果

页面最上面永远是当前用户的开头字母

实现代码如下:

 

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);

    int left = parent.getPaddingLeft();
    int right = parent.getWidth() - parent.getPaddingRight();

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View child = parent.getChildAt(i);
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
        int position = params.getViewAdapterPosition();
        if (position < 0 ){
            return;
        }
        String indexName = users.get(position).getFirstChar();
        if (indexName == null) {
            continue;
        }
        if (position > 0 && !TextUtils.equals(indexName, users.get(position - 1).getFirstChar())) {
            // 背景
            int top = child.getTop() - params.topMargin - mDecorationHeight;
            int bottom = top + mDecorationHeight;
            c.drawRect(left, top, right, bottom, mBgPaint);
            // 文字
            mTextPaint.getTextBounds(indexName, 0, indexName.length(), mTextBounds);
            int h = mTextBounds.height();
            c.drawText(indexName, left + textMarginLeft, bottom - (mDecorationHeight - h) / 2.0f, mTextPaint);
        }
    }
}
@Override
    public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        int firstVisibleItemPosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
        // 第一个也不展示decoration
//        if (firstVisibleItemPosition <= 0) {
//            return;
//        }

        boolean hasTrans = false;
        String indexName = users.get(firstVisibleItemPosition).getFirstChar();
        // 移动decoration
        if (firstVisibleItemPosition + 1 < users.size()) {
            String nextIndexName = users.get(firstVisibleItemPosition + 1).getFirstChar();
            if (!TextUtils.equals(indexName, nextIndexName)) {
                View firstVisibleChild = parent.getChildAt(0);
                int transY = firstVisibleChild.getBottom() - (parent.getPaddingTop() + mDecorationHeight);
                if (transY < 0) {
                    c.save();
                    c.translate(0, transY);
                    hasTrans = true;
                }
            }
        }
        float left = parent.getLeft();
        float top = parent.getPaddingTop();
        float right = parent.getWidth() - parent.getPaddingRight();
        float bottom = top + mDecorationHeight;
        // 背景
        c.drawRect(left, top, right, bottom, mBgPaint);
        mTextPaint.getTextBounds(indexName, 0, indexName.length(), mTextBounds);
        //文字
        float baseline = bottom - (mDecorationHeight - mTextBounds.height()) / 2.0f;
        c.drawText(indexName, parent.getPaddingLeft() + textMarginLeft, baseline, mTextPaint);
        if (hasTrans) {
            c.restore();
        }
    }
}

3.3头像功能的实现

将方形的图片转换为圆形的头像

实现代码如下:

public class CircleImageView extends androidx.appcompat.widget.AppCompatImageView {
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //由于是圆形,宽高应保持一致
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRadius = size / 2;
        setMeasuredDimension(size, size);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {

        mPaint = new Paint();

        Drawable drawable = getDrawable();

        if (null != drawable) {
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

            //初始化BitmapShader,传入bitmap对象
            BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            //计算缩放比例
            mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

            Matrix matrix = new Matrix();
            matrix.setScale(mScale, mScale);
            bitmapShader.setLocalMatrix(matrix);
            mPaint.setShader(bitmapShader);
            //画圆形,指定好坐标,半径,画笔
            canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
        } else {
            super.onDraw(canvas);
        }
    }
}

然后在我们设置的xml文件中添加我们创建的CircleImageView

<com.example.homework.CircleImageView
    android:id="@+id/imageView"
    android:layout_width="104dp"
    android:layout_height="102dp"
    app:srcCompat="@drawable/img1"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"/>

3.4点击事件的绑定

提示当前是什么用户

实现代码:

class MyVIewHolder extends RecyclerView.ViewHolder{
    TextView textView1;
    ImageView image;
    //初始化控件
    public MyVIewHolder(@NonNull View itemView) {
        super(itemView);
        textView1 = itemView.findViewById(R.id.textView2);
        image = itemView.findViewById(R.id.imageView);
        textView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,"当前点击查看的用户为:"+textView1.getText(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3.5联系人的换位以及删除

用于交换不同联系人的位置以及删除某些联系人

实现代码如下:

public class Callback extends ItemTouchHelper.Callback{
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView,
                            @NonNull RecyclerView.ViewHolder viewHolder) {
    // 设置拖动方向, 此处设置上下拖动事件
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    // 设置滑动方向, 此处设置左右侧滑事件
    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
    // 应用 拖动 和 滑动 设置
    return makeMovementFlags(dragFlags, swipeFlags);
}
**
 * 是否启用长按拖动功能
 * @return
 */
@Override
public boolean isLongPressDragEnabled() {
    return true;
}
/**
 * 拖动幅度设置
 * 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作
 * @param viewHolder
 * @return
 */
@Override
public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
    // 该案例中, 拖动操作只能上下进行
    // 拖动超过条目组件高度超过 0.8 倍, 即可触发拖动操作
    return 0.8f;
}
//调用设置的move移动方法
@Override
public void onMoved(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, int fromPos, @NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
  mAdapter.moveItem(viewHolder.getAdapterPosition(),target.getAdapterPosition());
}
/**
 * 是否启用滑动操作
 * @return 是否启用 true 启用, false 不启用
 */
@Override
public boolean isItemViewSwipeEnabled() {
    return true;
}
/**
 * 用户滑动距离, 设置的是比例值, 返回值为 0.5 , 就意味着滑动宽度/高度的一半, 才触发侧滑 onSwiped 方法
 * @param viewHolder
 * @return
 */
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
    return 0.5f;
}
/**
 * 滑动判定速度, 每秒移动的像素个数, 达到该速度后, 才可以被判定为滑动
 * @param defaultValue
 * @return
 */
@Override
public float getSwipeEscapeVelocity(float defaultValue) {
    return 5000f;
}
/**
 * 滑动时的回调操作
 * @param viewHolder
 * @param direction
 */
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
    Log.i(TAG, "触发侧滑删除条目");
    // 滑动指定的距离, 达到一定幅度后, 就会触发该方法回调
    // 这里做的是滑动删除功能, 直接删除滑动项
    // 该方法中删除指定条目, 并刷新界面
    mAdapter.deleteItem(viewHolder.getAdapterPosition());
}

4.小结

本次实验通过创建继承于ItemDecoration类的MyDecoration类并且重写其中的一些方法来实现了分隔线以及StickHeader的效果,通过创建继承于ImageView类的CircleViewImage类并重写其中的方法实现了圆形头像的作用,最后通过重写CallBack类中的某些方法来实现了最后的删除以及换位的功能。通过本次实验,更加清晰的了解了RecyclerView与Adapter的作用,以及其中的方法的实现。而且通过本次对recyclerView效果的实现,熟悉了ItemDecoration类以及Callback类的某些方法,对TextView,ImageView以及LinearLayout的使用更加的娴熟。

https://gitee.com/tao-jie/MyHomework

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值