前言:RecyclerView出来已经很久了,一直在用listView,也来尝试者在项目用一次RecyclerView,把一些心得拿出来分享一下,这里只用RecyclerView来做一个简单的列表展示,感觉还没有体现他的强大之处,相比listView,它少了分割线,点击后背景的变化,点击的回调接口,已经多了些设置。这里将:
- 列举出使用RecyclerView的基本步骤。
- 为RecyclerView添加分割线。
- 添加回调监听接口。
- 添加点击条目的水波纹效果。
一,使用RecyclerView的基本步骤:
- 添加gradle支持:
compile 'com.android.support:recyclerview-v7:23.1.1' - 在布局文件中使用:
<android.support.v7.widget.RecyclerView android:id="@+id/rv_left_menu_content" android:layout_width="match_parent" android:layout_height="240dp"/> - 编写条目的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> - 在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));
- 编写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;
}
@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);
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));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
this.getLocationOnScreen(mLocation);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if(mTargetView == null || !mShouldDoAnimation || mTargetWidth <= 0)
return;
if(mRevealRadius > mMinBetweenWidthAndHeight / 2)
mRevealRadius += mRevealRadiusGap * 4;
else
mRevealRadius += 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);
}
}
@Override
public 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;
else
return 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);
}
@Override
public void run() {
super.performClick();
}
@Override
public boolean performClick() {
postDelayed(this,40);
return true;
}
private class DispatchUpTouchEventRunnable implements Runnable{
public MotionEvent event;
@Override
public 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表示偏移的像素数。
本文详细介绍了如何在Android项目中使用RecyclerView替代ListView,包括添加分割线、实现回调监听、添加点击水波纹效果等基本操作,并提供了一套完整的示例代码。同时,解释了如何通过自定义Adapter来展示数据,以及如何获取屏幕尺寸来适配不同设备。
2446

被折叠的 条评论
为什么被折叠?



