Android的RecyclerView的初体验

来源:互联网 发布:美工 英文 编辑:程序博客网 时间:2024/05/02 01:29

前言:RecyclerView出来已经很久了,一直在用listView,也来尝试者在项目用一次RecyclerView,把一些心得拿出来分享一下,这里只用RecyclerView来做一个简单的列表展示,感觉还没有体现他的强大之处,相比listView,它少了分割线,点击后背景的变化,点击的回调接口,已经多了些设置。这里将:

  1. 列举出使用RecyclerView的基本步骤。
  2. 为RecyclerView添加分割线。
  3. 添加回调监听接口。
  4. 添加点击条目的水波纹效果。

一,使用RecyclerView的基本步骤:

  1. 添加gradle支持:
    compile 'com.android.support:recyclerview-v7:23.1.1'
  2. 在布局文件中使用:
    <android.support.v7.widget.RecyclerView                android:id="@+id/rv_left_menu_content"                android:layout_width="match_parent"                android:layout_height="240dp"/>
  3. 编写条目的item;
    <?xml version="1.0" encoding="utf-8"?><!--这里是引用了水波纹效果的布局,父类是一个linearLayout下面会展示源码--><com.wjustudio.phoneManager.widgt.RevealLayout    android:id="@+id/item_home"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal"    android:clickable="true"    android:background="@drawable/left_item_selector"    android:gravity="center_vertical">    <ImageView        android:id="@+id/img_icon"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="30dp"        android:src="@mipmap/icon_app"/>    <TextView        android:id="@+id/tv_icon_name"        android:layout_weight="1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_toRightOf="@id/img_icon"        android:text="应用管理"        android:textColor="@color/textColor"        android:textSize="20sp"/></com.wjustudio.phoneManager.widgt.RevealLayout></span>
  4. 在activity中使用,并添加相应的配置:
    //先通过findviewbyid或注解的方式得到RecyclerView的对象:mRvLeftMenuContent//设置RecyclerView// 创建一个线性布局管理器LinearLayoutManager layoutManager = new LinearLayoutManager(this);//设置垂直滚动,也可以设置横向滚动layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//RecyclerView设置布局管理器mRvLeftMenuContent.setLayoutManager(layoutManager);//设置侧拉菜单的recyclerView的布局mRvLeftMenuContent.setAdapter(new LeftMenuAdapter(mContext, mLeftPageIcons, windowSize));

  5. 编写adapter:
    import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import com.wjustudio.phoneManager.R;import com.wjustudio.phoneManager.javaBean.IconInfo;import java.util.HashMap;import java.util.List;/** * 左侧菜单对应的viewHolder */public class LeftMenuAdapter extends RecyclerView.Adapter {    private Context mContext;    private List<IconInfo> mLeftPageIcons;    private int mWindowHeight;    private int mWindowWidth;        public LeftMenuAdapter(Context context, List<IconInfo> leftPageIcons,  HashMap<String, Integer> windowSize) {        mContext = context;        mLeftPageIcons = leftPageIcons;        mWindowHeight = windowSize.get("height");        mWindowWidth = windowSize.get("width");    }    /**     * 自定义的ViewHolder,持有每个Item的的所有界面元素     */    public class NormalViewHolder extends RecyclerView.ViewHolder {        ImageView icon;        TextView iconName;        public NormalViewHolder(View itemView) {            super(itemView);            icon = (ImageView) itemView.findViewById(R.id.img_icon);            iconName = (TextView) itemView.findViewById(R.id.tv_icon_name);            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) icon.getLayoutParams();            params.height = mWindowHeight / 9;            icon.setLayoutParams(params);            params = (LinearLayout.LayoutParams) iconName.getLayoutParams();            params.width = mWindowWidth - icon.getWidth();            iconName.setLayoutParams(params);        }    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //在该方法中我们创建一个ViewHolder并返回,ViewHolder必须有一个带有View的构造函数,        //这个View就是我们Item的根布局,在这里我们使用自定义Item的布局;        View item = View.inflate(mContext, R.layout.item_left, null);        return new NormalViewHolder(item);    }    @Override    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {        //将数据与界面进行绑定的操作        NormalViewHolder normalHolder = (NormalViewHolder) holder;        normalHolder.icon.setImageResource(mLeftPageIcons.get(position).icon);        normalHolder.iconName.setText(mLeftPageIcons.get(position).iconName);        }    }    @Override    public int getItemCount() {        //获取数据的数量        return mLeftPageIcons == null ? 0 : mLeftPageIcons.size();    }}

             windowSize放的是屏幕的宽高,这里是为了设置条目的宽度,是这样的的到的:

            

   /**     * 获得宽度和除去通知栏的屏幕的高度     * @param activity     * @return     */    public static HashMap<String,Integer> getWindowSize(Activity activity){        WindowManager wm = activity.getWindowManager();        DisplayMetrics metrics = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(metrics);        int width = metrics.widthPixels;        int height = metrics.heightPixels;        height -= getStatusBarHeight(activity);        HashMap<String,Integer> windowSize = new HashMap<>();        windowSize.put("height",height);        windowSize.put("width",width);        return windowSize;    }    /**     * 获得状态栏的高度     * @param activity     * @return     */    public static int getStatusBarHeight(Activity activity){        int statusHeight = 0;        Rect frame = new Rect();        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);        statusHeight = frame.top;        if (0 == statusHeight){            Class<?> localClass;            try {                localClass = Class.forName("com.android.internal.R$dimen");                Object localObject = localClass.newInstance();                int i5 = Integer.parseInt(localClass.getField("status_bar_height").                        get(localObject).toString());                statusHeight = activity.getResources().getDimensionPixelSize(i5);            } catch (ClassNotFoundException e) {                e.printStackTrace();            } catch (IllegalAccessException e) {                e.printStackTrace();            } catch (InstantiationException e) {                e.printStackTrace();            } catch (NoSuchFieldException e) {                e.printStackTrace();            }        }        return statusHeight;    }

二,为RecyclerView添加分割线:

编写类

package com.wjustudio.phoneManager.widgt;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;/** * This class is from the v7 samples of the Android SDK. It's not by me! * <p/> * See the license above for details. */public class DividerItemDecoration extends RecyclerView.ItemDecoration {    private static final int[] ATTRS = new int[]{            android.R.attr.listDivider    };    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;    private Drawable mDivider;    private int mOrientation;    public DividerItemDecoration(Context context, int orientation) {        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();        setOrientation(orientation);    }    public void setOrientation(int orientation) {        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {            throw new IllegalArgumentException("invalid orientation");        }        mOrientation = orientation;    }    @Override    public void onDraw(Canvas c, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            drawVertical(c, parent);        } else {            drawHorizontal(c, parent);        }    }    public void drawVertical(Canvas c, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getWidth() - parent.getPaddingRight();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());            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);        }    }    public void drawHorizontal(Canvas c, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getHeight() - parent.getPaddingBottom();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int left = child.getRight() + params.rightMargin;            final int right = left + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        }    }}

在RecyclerView中添加:

//添加分割线mRvLeftMenuContent.addItemDecoration(new DividerItemDecoration(        this, DividerItemDecoration.VERTICAL_LIST));

三,添加回调监听接口:

   /**     * 点击事件的监听接口     */    public interface OnItemClickListener{        void onItemClick(View view, int position);    }    private OnItemClickListener mOnItemClickLitener;    public void setOnItemClicklistener(OnItemClickListener listener){        mOnItemClickLitener = listener;    }

@Overridepublic void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {        //将数据与界面进行绑定的操作        NormalViewHolder normalHolder = (NormalViewHolder) holder;        normalHolder.icon.setImageResource(mLeftPageIcons.get(position).icon);        normalHolder.iconName.setText(mLeftPageIcons.get(position).iconName);        if (mOnItemClickLitener != null){            holder.itemView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    mOnItemClickLitener.onItemClick(holder.itemView,position);                }            });        }}

四,添加条目点击的水波纹效果:

package com.wjustudio.phoneManager.widgt;import android.annotation.TargetApi;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.os.Build;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.LinearLayout;import com.wjustudio.phoneManager.R;import java.util.ArrayList;public class RevealLayout extends LinearLayout implements Runnable{private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private float mCenterX,mCenterY;private int[] mLocation = new int[2];private int INVALIDATE_DURATION = 40;private int mTargetHeight,mTargetWidth;private int mRevealRadius = 0,mRevealRadiusGap,mMaxRadius;private int mMinBetweenWidthAndHeight,mMaxBetweenWidthAndHeight;private boolean mIsPressed;private boolean mShouldDoAnimation;private View mTargetView;private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();public RevealLayout(Context context) {super(context);init();}public RevealLayout(Context context, AttributeSet attrs){super(context,attrs);init();}@TargetApi(Build.VERSION_CODES.HONEYCOMB)public RevealLayout(Context context, AttributeSet attrs, int defStyleAttr){super(context,attrs,defStyleAttr);init();}public void init(){setWillNotDraw(false);mPaint.setColor(getResources().getColor(R.color.reveal_color));}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);this.getLocationOnScreen(mLocation);}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);if(mTargetView == null || !mShouldDoAnimation || mTargetWidth <= 0)return;if(mRevealRadius > mMinBetweenWidthAndHeight / 2)mRevealRadius += mRevealRadiusGap * 4;elsemRevealRadius += mRevealRadiusGap;int[] location = new int[2];this.getLocationOnScreen(mLocation);mTargetView.getLocationOnScreen(location);int top = location[1] - mLocation[1];int left = location[0] - mLocation[0];int right = left + mTargetView.getMeasuredWidth();int bottom = top + mTargetView.getMeasuredHeight();canvas.save();canvas.clipRect(left, top, right, bottom);canvas.drawCircle(mCenterX, mCenterY, mRevealRadius, mPaint);canvas.restore();if(mRevealRadius <= mMaxRadius)postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);else if(!mIsPressed){mShouldDoAnimation = false;postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);}}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {int x = (int)event.getRawX();int y = (int)event.getRawY();int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:View targetView = getTargetView(this,x,y);if(targetView != null && targetView.isEnabled()){mTargetView = targetView;initParametersForChild(event,targetView);postInvalidateDelayed(INVALIDATE_DURATION);}break;case MotionEvent.ACTION_UP:mIsPressed = false;postInvalidateDelayed(INVALIDATE_DURATION);mDispatchUpTouchEventRunnable.event = event;postDelayed(mDispatchUpTouchEventRunnable, 40);break;case MotionEvent.ACTION_CANCEL:mIsPressed = false;postInvalidateDelayed(INVALIDATE_DURATION);break;}return super.dispatchTouchEvent(event);}public View getTargetView(View view,int x,int y){View target = null;ArrayList<View> views = view.getTouchables();for(View child : views)if(isTouchPointInView(child,x,y)){target = child;break;}return target;}public boolean isTouchPointInView(View child,int x,int y){int[] location = new int[2];child.getLocationOnScreen(location);int top = location[1];int left = location[0];int right = left + child.getMeasuredWidth();int bottom = top + child.getMeasuredHeight();if(child.isClickable() && y>=top && y<= bottom && x >= left && x<= right)return true;elsereturn false;}public void initParametersForChild(MotionEvent event,View view){mCenterX = event.getX();mCenterY = event.getY();mTargetWidth = view.getMeasuredWidth();mTargetHeight = view.getMeasuredHeight();mMinBetweenWidthAndHeight = Math.min(mTargetWidth, mTargetHeight);mMaxBetweenWidthAndHeight = Math.max(mTargetWidth, mTargetHeight);mRevealRadius = 0;mRevealRadiusGap = mMinBetweenWidthAndHeight / 8;mIsPressed = true;mShouldDoAnimation = true;int[] location = new int[2];view.getLocationOnScreen(location);int left = location[0] - mLocation[0];int mTransformedCenterX = (int)mCenterX - left;mMaxRadius = Math.max(mTransformedCenterX, mTargetWidth - mTransformedCenterX);}@Overridepublic void run() {super.performClick();}@Overridepublic boolean performClick() {postDelayed(this,40);return true;}private class DispatchUpTouchEventRunnable implements Runnable{public MotionEvent event;@Overridepublic void run() {if(mTargetView.isEnabled() && mTargetView.isClickable())return;if(isTouchPointInView(mTargetView, (int)event.getRawX(), (int)event.getRawX()))mTargetView.performClick();}}}

使用这个类作为条目的父控件就可以了。

点击的时候为了有颜色变化还应该为条目设置背景的selector:

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:drawable="@drawable/reveal_color" android:state_pressed="true"/>    <item android:drawable="@drawable/reveal_color" android:state_checked="true"/>    <item android:drawable="@drawable/left_bg_color"/></selector>
对应的颜色值为:

 <drawable name="reveal_color">#1b000000</drawable> <drawable name="left_bg_color">#E7E5E4</drawable>


RecycleView中替代ListView中的setselection的方法:

((LinearLayoutManager)mRecyclerView.getLayoutManager()).scrollToPositionWithOffset(i,0);

其中的i表示第i个条目,0表示偏移的像素数。



1 0
原创粉丝点击