目录

演示

使用方式
①加入SwipeRecycler.java

②布局
<com.github.pgycode.swiperecycler.SwipeRecycler
android:layout_width="match_parent"
android:id="@+id/recycler"
android:layout_height="match_parent">
</com.github.pgycode.swiperecycler.SwipeRecycler>
③子view布局样例
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_height="70dp">
<!--假设这个textview是主view-->
<TextView
android:id="@+id/txt"
android:layout_width="360dp"
android:text="测试swipeRecycler"
android:gravity="center"
android:textSize="17sp"
android:textStyle="bold"
android:textColor="#000000"
android:background="#ffffff"
android:layout_height="70dp" />
<Button
android:layout_width="90dp"
android:layout_height="70dp"
android:gravity="center"
android:text="置顶"
android:id="@+id/btn_top"
android:background="#c8c7c7"
android:textColor="#ffffff"
android:textSize="17sp" />
<Button
android:layout_width="90dp"
android:layout_height="70dp"
android:gravity="center"
android:text="删除"
android:id="@+id/btn_del"
android:background="#e94637"
android:textColor="#ffffff"
android:textSize="17sp" />
</LinearLayout>
<!--这是分割线-->
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/colorPrimary"/>
</LinearLayout>
④子view的尺寸----这里要分别设置子view与子view内部主view的宽度。
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, recycler, false);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = recycler.getScreenWidth() + recycler.dp2px(180);
view.setLayoutParams(layoutParams);
//这里假设这个txt是主view
View main = view.findViewById(R.id.txt);
ViewGroup.LayoutParams mainLayoutParams = main.getLayoutParams();
mainLayoutParams.width = recycler.getScreenWidth();
main.setLayoutParams(mainLayoutParams);
return new ViewHolder(view);
}
⑤设置点击事件记得先关闭菜单
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recycler.closeEx();
Snackbar.make(MainActivity.this.findViewById(R.id.root), position + "",
Snackbar.LENGTH_SHORT).show();
}
});
思路
1.整体思路
设置paddingLeft为负值,实现弹出菜单。
//移动距离
public int distance = 0;
2.如何区分横向滑动和竖向滑动。
滑动开始时设置阈值为50去判断,是什么滑动,只有大于50才判定是什么滑动。
//是否在拖动
public boolean isSwipe = false;
//是否在滚动
private boolean isSroll = false;
3.处理滑动时候的多种情况。
分情况处理
①向左 在里面
②向左 在外面
③向右 在外面
④向右 在里面
//是否需要向右
private boolean toRight = false;
//是否需要向左
private boolean toLeft = false;
4.滑动事件与点击事件冲突。
滑动事件的状态处理写在dispatchTouchEvent里面,控制下发事件
滑动事件的页面处理写在onTouchEvent里面。
5.view宽度如何设置。
自行设置
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, recycler, false);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = recycler.getScreenWidth() + recycler.dp2px(180);
view.setLayoutParams(layoutParams);
View main = view.findViewById(R.id.txt);
ViewGroup.LayoutParams mainLayoutParams = main.getLayoutParams();
mainLayoutParams.width = recycler.getScreenWidth();
main.setLayoutParams(mainLayoutParams);
代码
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/root"
android:layout_height="match_parent">
<com.github.pgycode.swiperecycler.SwipeRecycler
android:layout_width="match_parent"
android:id="@+id/recycler"
android:layout_height="match_parent">
</com.github.pgycode.swiperecycler.SwipeRecycler>
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_height="70dp">
<!--假设这个textview是主view-->
<TextView
android:id="@+id/txt"
android:layout_width="360dp"
android:text="测试swipeRecycler"
android:gravity="center"
android:textSize="17sp"
android:textStyle="bold"
android:textColor="#000000"
android:background="#ffffff"
android:layout_height="70dp" />
<Button
android:layout_width="90dp"
android:layout_height="70dp"
android:gravity="center"
android:text="置顶"
android:id="@+id/btn_top"
android:background="#c8c7c7"
android:textColor="#ffffff"
android:textSize="17sp" />
<Button
android:layout_width="90dp"
android:layout_height="70dp"
android:gravity="center"
android:text="删除"
android:id="@+id/btn_del"
android:background="#e94637"
android:textColor="#ffffff"
android:textSize="17sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/colorPrimary"/>
</LinearLayout>
SwipeActivity.Java
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class SwipeRecycler extends RecyclerView {
//移动距离
public int distance = 0;
//是否在拖动
public boolean isSwipe = false;
//是否需要向右
private boolean toRight = false;
//是否需要向左
private boolean toLeft = false;
//是否在滚动
private boolean isSroll = false;
//开始的x
private float startx;
//开始的y
private float starty;
//现在的
private int add = -1;
//多出尺寸
private int exSize;
private LinearLayoutManager layoutManager;
private Context context;
public SwipeRecycler(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
layoutManager = new LinearLayoutManager(context);
setLayoutManager(layoutManager);
this.context = context;
//确认滚动停止
addOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == SCROLL_STATE_IDLE){
isSroll = false;
}
}
});
}
/**
* 返回 false 不作处理 但是也不禁止它上传
* @param e
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_MOVE){
int movex = (int) (e.getX() - startx);
int movey = (int) (e.getY() - starty);
//滑动范围过小,不作用于view
if (Math.abs(movey) < 50 && Math.abs(movex) < 50) {
return false;
}
if (isSroll){
return super.onTouchEvent(e);
}
if (isSwipe && toLeft){
distance = movex;
move();
}
if (isSwipe && toRight){
distance = -exSize + movex;
move();
}
return false;
}
if (isSwipe){
return false;
}
return super.onTouchEvent(e);
}
private void move(){
if (distance > 0){
distance = 0;
} if (distance < -exSize){
distance = -exSize;
}
if (add != -1) {
View view = findViewHolderForAdapterPosition(add).itemView;
setPaddingLeft(view, distance);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (isSwipe || isSroll){
return true;
}
return super.onInterceptTouchEvent(e);
}
@Override
public boolean dispatchTouchEvent(MotionEvent e) {
/**
* 按下事件
* 只记录按下之后的坐标
*/
if (e.getAction() == MotionEvent.ACTION_DOWN){
startx = e.getX();
starty = e.getY();
}
/**
* 移动事件
*/
else if (e.getAction() == MotionEvent.ACTION_MOVE){
int movex = (int) (e.getX() - startx);
int movey = (int) (e.getY() - starty);
if (!isSwipe && !isSroll && Math.abs(movex) > 50){
isSwipe = true;
//向右 在外面
if (movex > 0 && distance < 0){
toRight = true;
toLeft = false;
}
//向左 在里面
else if (movex < 0 && distance == 0){
int temp = getPosition(e);
if (temp != -1){
add = temp;
exSize = findViewHolderForAdapterPosition(add).itemView.getWidth() - getWidth();
toRight = false;
toLeft = true;
}
}
//向左 在外面
else if (movex < 0 && distance < 0){
int temp = getPosition(e);
if (temp != -1 && temp != add) {
playLastBack();
add = temp;
exSize = findViewHolderForAdapterPosition(add).itemView.getWidth() - getWidth();
toRight = false;
toLeft = true;
}
} else {
toRight = false;
toLeft = false;
}
} else if (!isSroll && !isSwipe && Math.abs(movey) > 50){
isSroll = true;
closeEx();
}
System.out.println(isSroll + " " + isSwipe + " " + toLeft + " " + toRight + " " + distance + " " + movex + " " + movey);
} else {
if (toRight){
if (distance > -2 * exSize / 3){
playBack(distance, 0);
} else {
playBack(distance, -exSize);
}
}
if (toLeft){
if (distance < -exSize / 3){
playBack(distance, -exSize);
} else {
playBack(distance, 0);
}
}
else{
initData();
}
}
return super.dispatchTouchEvent(e);
}
private void playBack(int start, final int end){
final ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.setDuration(Math.abs(end - start) / 3);
final View view = findViewHolderForAdapterPosition(add).itemView;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (add != -1) {
setPaddingLeft(view, (Integer) valueAnimator.getAnimatedValue());
distance = (int) valueAnimator.getAnimatedValue();
}
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if (end == 0){
initData();
add = -1;
} else {
initData();
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.start();
}
public void playLastBack(){
final View view = findViewHolderForAdapterPosition(add).itemView;
if (view != null) {
final ValueAnimator animator = ValueAnimator.ofInt(-exSize, 0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
setPaddingLeft(view, (Integer) valueAnimator.getAnimatedValue());
}
});
animator.start();
}
}
private int getPosition(MotionEvent e){
int f = layoutManager.findFirstVisibleItemPosition();
int l = layoutManager.findLastVisibleItemPosition();
for (int i = f; i <= l; i++){
View view = findViewHolderForAdapterPosition(i).itemView;
int[] location = new int[2];
view.getLocationOnScreen(location);
if (e.getY() < location[1] && e.getY() > location[1] - view.getHeight() && e.getX() > location[0] && e.getX() < location[0] + view.getWidth()) {
return i;
}
}
return -1;
}
private void initData(){
isSwipe = false;
startx = 0;
starty = 0;
toRight = false;
toLeft = false;
}
public void closeEx(){
ViewHolder viewHolder = findViewHolderForAdapterPosition(add);
if (viewHolder != null){
View view = viewHolder.itemView;
add = -1;
distance = 0;
view.setPadding(0, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
}
public int getScreenWidth(){
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
/*
* dp转换成px
*/
public int dp2px(int dp){
float scale = context.getResources().getDisplayMetrics().density;
return (int)(dp * scale + 0.5f);
}
private void setPaddingLeft(View view, int left){
view.setPadding(left, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
}
MainActivity.java
package com.github.pgycode.swiperecycler;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private SwipeRecycler recycler;//工具类
private List<String> strings;//模拟数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
strings = new ArrayList<>();
for (int i = 0; i < 100; i++){
strings.add("test sentence : " + i);
}
recycler = findViewById(R.id.recycler);
recycler.setAdapter(new RecyclerView.Adapter<ViewHolder>() {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, recycler, false);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = recycler.getScreenWidth() + recycler.dp2px(180);
view.setLayoutParams(layoutParams);
View main = view.findViewById(R.id.txt);
ViewGroup.LayoutParams mainLayoutParams = main.getLayoutParams();
mainLayoutParams.width = recycler.getScreenWidth();
main.setLayoutParams(mainLayoutParams);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
//请注意,为了有良好的体验,请记得每次点击事件生效时,关闭菜单
//recycler.closeEx();
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recycler.closeEx();
Snackbar.make(MainActivity.this.findViewById(R.id.root), position + "", Snackbar.LENGTH_SHORT).show();
}
});
holder.txt.setText(strings.get(position));
holder.btnDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recycler.closeEx();
//模拟删除
strings.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(0, strings.size());
}
});
holder.btnTop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recycler.closeEx();
//模拟置顶
String temp = strings.remove(position);
strings.add(0, temp);
notifyItemChanged(position, 0);
notifyItemRangeChanged(0, strings.size());
}
});
}
@Override
public int getItemCount() {
return strings.size();
}
});
}
private class ViewHolder extends RecyclerView.ViewHolder {
private Button btnDel;
private Button btnTop;
private TextView txt;
public ViewHolder(@NonNull View itemView) {
super(itemView);
btnDel = itemView.findViewById(R.id.btn_del);
btnTop = itemView.findViewById(R.id.btn_top);
txt = itemView.findViewById(R.id.txt);
}
}
}
网友评论