RecyclerView : 回收和定位屏幕上的view
ViewHolder : 容纳View视图
Adapter : 创建并绑定ViewHolder至模型层数据
1.添加依赖
implementation 'com.android.support:appcompat-v7:26.1.0'
// implementation 'com.android.support:recyclerview-v7:26.1.0'
2.新建ViewHolder与Adapter
public class DemoAdapter extends RecyclerView.Adapter<DemoAdapter.ViewHolder> {
private List<DemoBean> mDemoBeanList;
public DemoAdapter(List<DemoBean> demoBeanList) {
mDemoBeanList = demoBeanList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.demo_bean,parent,false);
ViewHolder viewHolder=new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
DemoBean demoBean=mDemoBeanList.get(position);
holder.mImageView.setImageResource(demoBean.getImageId());
holder.mTextView.setText(demoBean.getMsg());
}
@Override
public int getItemCount() {
return mDemoBeanList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
mImageView=(ImageView) itemView.findViewById(R.id.imageview);
mTextView=(TextView) itemView.findViewById(R.id.textview);
}
}
}
3.配置LayoutManager & Adapter
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recyclerview);
//GridLayoutManager 实现网格布局 StaggeredGridLayoutManager实现瀑布流布局
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
DemoAdapter demoAdapter=new DemoAdapter(mDemoBeanList);
recyclerView.setAdapter(demoAdapter);
}
S: ItemTouchHelper实现滑动删除
final ItemTouchHelper helper=new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN;
int swipFlags=ItemTouchHelper.END|ItemTouchHelper.START;
return makeMovementFlags(dragFlags,swipFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int from=viewHolder.getAdapterPosition();
int to=target.getAdapterPosition();
Collections.swap(mPicList,from,to);
recyclerView.getAdapter().notifyItemMoved(from,to);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position=viewHolder.getAdapterPosition();
m.getAdapter().notifyItemRemoved(position);
mPicList.remove(position);
}
});
helper.attachToRecyclerView(m);
SS: 自定义ViewGroup实现滑动删除
1.自定义ViewGroup
public class MySlidingItemView extends ViewGroup {
private View leftView;
private View rightView;
private ViewDragHelper mHelper;
private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if(changedView==leftView){
rightView.layout(rightView.getLeft()+dx,0,rightView.getRight()+dx,rightView.getBottom()+dy);
}else if(changedView==rightView){
leftView.layout(leftView.getLeft()+dx,0,leftView.getRight()+dx,leftView.getBottom()+dy);
}
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if(child==leftView){
if(left>=0){
left=0;
}else if(left<=-rightView.getMeasuredWidth()){
left=-rightView.getMeasuredWidth();
}
}else if(child==rightView){
if(left<=leftView.getMeasuredWidth()-rightView.getMeasuredWidth()){
left=leftView.getMeasuredWidth()-rightView.getMeasuredWidth();
}else if(left>=leftView.getMeasuredWidth()){
left=leftView.getMeasuredWidth();
}
}
return left;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if(releasedChild==leftView){
if(rightView.getLeft()<getMeasuredWidth()-rightView.getMeasuredWidth()/2){
mHelper.smoothSlideViewTo(rightView,getMeasuredWidth()-rightView.getMeasuredWidth(),0);
invalidate();
}else{
mHelper.smoothSlideViewTo(rightView,getMeasuredWidth(),0);
invalidate();
}
}
}
};
public MySlidingItemView(Context context) {
this(context,null);
}
public MySlidingItemView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MySlidingItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHelper=ViewDragHelper.create(this,callback);
}
@Override
public void computeScroll() {
if(mHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec,heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
leftView=getChildAt(0);
rightView=getChildAt(1);
leftView.layout(0,0,leftView.getMeasuredWidth(),leftView.getMeasuredHeight());
rightView.layout(leftView.getMeasuredWidth(),0,leftView.getMeasuredWidth()+
rightView.getMeasuredWidth(),rightView.getMeasuredHeight());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mHelper.processTouchEvent(event);
return true;
}
}
2.item布局
<com.kangcreator.myapplication.MySlidingItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="80dp"
xmlns:Tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="centerCrop"
Tools:src="@drawable/t13"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:gravity="bottom"
android:text="Hi.............................."
android:textColor="#36a11e"
android:textSize="30sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/del"
android:layout_width="100dp"
android:layout_height="80dp"
android:text="del"
android:textColor="#103c89"
android:textSize="30sp"/>
<Button
android:layout_width="100dp"
android:layout_height="80dp"
android:text="del"
android:textColor="#103c89"
android:textSize="30sp"/>
</LinearLayout>
</com.kangcreator.myapplication.MySlidingItemView>
3.Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<Pic> mPicList;
private Context mContext;
public MyAdapter(List<Pic> picList, Context context) {
mPicList = picList;
mContext=context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v= LayoutInflater.from(mContext).inflate(R.layout.slidingview,parent,false);
ViewHolder viewHolder=new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Pic pic=mPicList.get(position);
holder.mImageView.setImageResource(pic.getId());
holder.mDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPicList.remove(position);
notifyDataSetChanged();
}
});
}
@Override
public int getItemCount() {
return mPicList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView mImageView;
private Button mDel;
public ViewHolder(View itemView) {
super(itemView);
mImageView= itemView.findViewById(R.id.image);
mDel=itemView.findViewById(R.id.del);
}
}
}
4.MainActivity
public class MainActivity extends AppCompatActivity {
private List<Pic> mPicList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RecyclerView m=findViewById(R.id.recyclerview);
Pic pic=new Pic(R.drawable.t0);
mPicList.add(pic);
pic=new Pic(R.drawable.t1);
mPicList.add(pic);
pic=new Pic(R.drawable.t2);
mPicList.add(pic);
pic=new Pic(R.drawable.t4);
mPicList.add(pic);
pic=new Pic(R.drawable.t6);
mPicList.add(pic);
pic=new Pic(R.drawable.t9);
mPicList.add(pic);
pic=new Pic(R.drawable.t10);
mPicList.add(pic);
pic=new Pic(R.drawable.t13);
mPicList.add(pic);
pic=new Pic(R.drawable.t14);
mPicList.add(pic);
RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(this);
m.setLayoutManager(layoutManager);
m.setAdapter(new MyAdapter(mPicList,this));
// m.setOndelListener(new MyRecyclerView.OnDelActivatedListener() {
// @Override
// public void ondel(int position) {
// m.getAdapter().notifyItemRemoved(position);
// mPicList.remove(position);
// m.getAdapter().notifyItemRangeChanged(position,mPicList.size());
// }
// });
final ItemTouchHelper helper=new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN;
// int swipFlags=ItemTouchHelper.END|ItemTouchHelper.START;
return makeMovementFlags(dragFlags,0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int from=viewHolder.getAdapterPosition();
int to=target.getAdapterPosition();
Collections.swap(mPicList,from,to);
recyclerView.getAdapter().notifyItemMoved(from,to);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// int position=viewHolder.getAdapterPosition();
// m.getAdapter().notifyItemRemoved(position);
// mPicList.remove(position);
}
});
helper.attachToRecyclerView(m);
}
}
XXX:
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mItemLayout==null ||mItemLayout.getScrollX()!=0){
return true;
}
break;
}
return super.onTouchEvent(e);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
mVelocityTracker.addMovement(e);
int x = (int) e.getX();
int y = (int) e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(isItemMoving);
if (mDeleteBtnState == 0) {
View view = findChildViewUnder(x, y);
if (view == null) {
return false;
}
ViewHolder viewHolder = getChildViewHolder(view);
mItemLayout = viewHolder.itemView;
mItemLayout.setClickable(true);
mPosition = viewHolder.getAdapterPosition();
mDelete = (TextView) mItemLayout.findViewById(item_delete);
mMaxLength = mDelete.getWidth();
mDelete.setOnClickListener(v -> {
mListener.onItemClick(v,mPosition);
mItemLayout.scrollTo(0, 0);
mDeleteBtnState = 0;
});
} else if (mDeleteBtnState == 3){
mScroller.startScroll(mItemLayout.getScrollX(), 0, -mMaxLength, 0, 200);
invalidate();
mDeleteBtnState = 0;
return false;
}else{
return false;
}
break;
case MotionEvent.ACTION_MOVE:
int dx = mLastX - x;
int dy = mLastY - y;
if(dy<80 && x>=mItemLayout.getWidth()/2 || mItemLayout.getScrollX()>0){
isItemMoving=true;
int scrollX = mItemLayout.getScrollX();
if (Math.abs(dx) > Math.abs(dy)) {//左边界检测
if (scrollX + dx <= 0) {
mItemLayout.scrollTo(0, 0);
return true;
} else if (scrollX + dx >= mMaxLength) {//右边界检测
mItemLayout.scrollTo(mMaxLength, 0);
return true;
}
mItemLayout.scrollBy(dx, 0);//item跟随手指滑动
}
}else{
isItemMoving=false;
}
getParent().requestDisallowInterceptTouchEvent(isItemMoving);
return false;
case MotionEvent.ACTION_UP:
mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度
float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)
float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度
int deltaX = 0;
int upScrollX = mItemLayout.getScrollX();
if (Math.abs(xVelocity) > 100 && Math.abs(xVelocity) > Math.abs(yVelocity)) {
if (xVelocity <= -100) {//左滑速度大于100,则删除按钮显示
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
} else if (xVelocity > 100) {//右滑速度大于100,则删除按钮隐藏
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
} else {
if (upScrollX >= mMaxLength / 2) {//item的左滑动距离大于删除按钮宽度的一半,则则显示删除按钮
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
} else if (upScrollX < mMaxLength / 2) {//否则隐藏
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
}
//item自动滑动到指定位置
mScroller.startScroll(upScrollX, 0, deltaX, 0, 200);
isStartScroll = true;
getParent().requestDisallowInterceptTouchEvent(false);
mVelocityTracker.clear();
break;
}
mLastX = x;
mLastY = y;
return super.onInterceptTouchEvent(e);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mItemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
} else if (isStartScroll) {
isStartScroll = false;
if (mDeleteBtnState == 1) {
mDeleteBtnState = 0;
}
if (mDeleteBtnState == 2) {
mDeleteBtnState = 3;
}
}
}
@Override
protected void onDetachedFromWindow() {
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
isDragging = state == SCROLL_STATE_DRAGGING;
}