溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在android中使用View實現(xiàn)一個滑動刪除效果

發(fā)布時間:2020-11-25 17:17:49 來源:億速云 閱讀:444 作者:Leah 欄目:移動開發(fā)

這篇文章給大家介紹怎么在android中使用View實現(xiàn)一個滑動刪除效果,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

實現(xiàn)功能

1、可以向左滑動,右側出現(xiàn)刪除
2、向左滑動如果刪除出現(xiàn)一大半,松手打開刪除,反之關閉刪除
3、應用場景
          微信消息的刪除功能

實現(xiàn)原理

1、外面是一個ListView
2、條目是一個自定義控件繼承ViewGroup
    1)、左邊一個TextView,右側屏幕外也有一個TextView
    2)、所以繼承ViewGroup

實現(xiàn)步驟

1、創(chuàng)建一個SlideDeleteView類

    1).構造方法要關聯(lián)

public class SlideDelete extends ViewGroup {

 private View leftView;
 private View rightView;
 private ViewDragHelper helper;

 //第一步關聯(lián)構造方法
 //第二步重寫onMeasure和onLViewayout測量子View和布局子View
 public SlideDelete(Context context) {
  this(context,null);
 }

 public SlideDelete(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }

 public SlideDelete(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);

  helper = ViewDragHelper.create(this, callback);

 }
}

2、在布局文件中設置SlideDeleteView里面的子View

    SlideDeleteView height=80

        TextView
            width:matchParent
            height:matchparent
        TextView

<com.example.movedelete.SlideDelete
  android:id="@+id/container"
  android:layout_width="match_parent"
  android:layout_height="80dp">

  <TextView

   android:id="@+id/content"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center"
   android:background="#33000000"
   android:text="第0個條目"
   android:textColor="#fff"
   android:textSize="20sp" />
  <TextView

   android:id="@+id/delete"
   android:layout_width="80dp"
   android:layout_height="match_parent"
   android:background="#f00"
   android:gravity="center"
   android:text="刪除"
   android:textColor="#fff"
   android:textSize="20sp" />

 </com.example.movedelete.SlideDelete>

3、重寫onMeasure,給子View進行測量

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  //對當前組合View的測量,不使用的話,也可以自己設置
  measureChildren(widthMeasureSpec,heightMeasureSpec);
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

 }

4、重寫onLayout,給子View進行布局

注意事項:要設置leftView,也要設置rightView,不要都寫成leftView了

 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  //第一步獲取里面子View
  leftView = getChildAt(0);
  rightView = getChildAt(1);
  //第二步給子View提供相應的布局
  int leftL = 0;
  int leftT = 0;
  int leftR = leftView.getMeasuredWidth();
  int leftB = leftView.getMeasuredHeight();
  leftView.layout(leftL,leftT,leftR,leftB);

  //給rightView提供相應的布局
  int rightL = leftView.getMeasuredWidth();
  int rightT = 0;
  int rightR = leftView.getMeasuredWidth()+ rightView.getMeasuredWidth();
  int rightB = rightView.getMeasuredHeight();
  rightView.layout(rightL,rightT,rightR,rightB);

 }

5、設置View的滑動事件onTouchEvent,實現(xiàn)滑動
    1).因為要滑動,所以消費該事件返回true
    2).使用ViewDragHelper來實現(xiàn)滑動效果

注意事項:

只能實現(xiàn)leftView的滑動,右側RightView看不到所以滑動不了

只能給滑動的View設置監(jiān)聽,當滑動的時候,重新設置另一個View的布局跟著滑動

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //1,要消費該事件,所以直接返回true
  //2,使用ViewDragHelper來實現(xiàn)滑動效果
  helper.processTouchEvent(event);
  return true;
 }

6、重寫滑動事件的監(jiān)聽onViewPositionChanged解決只有l(wèi)efView滑動的問題

    1).重寫的方法是在ViewDragHelper.Callback的子實現(xiàn)類中

    2).要實現(xiàn)滑動事件,必須在tryCaptureView方法中返回true

 private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
  //手勢滑動時
  @Override
  public boolean tryCaptureView(View child, int pointerId) {
   return true;
  }
  //監(jiān)聽控件移動狀態(tài)
  @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);
   }


  }

7、重寫clampViewPositionHorizontal水平位置移動,解決左右越界問題

    1.返回值為移動時左側滑動的距離
    2.如果滑動的控件是leftView時,解決越界
    3.如果滑動的控件是rightView時,解決越界

 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){
    //只處理右邊的越界問題,因為左側越界的時看不到該View
    if(left <= leftView.getMeasuredWidth()- rightView.getMeasuredWidth()){
     left = leftView.getMeasuredWidth()- rightView.getMeasuredWidth();
    }else if(left >= leftView.getMeasuredWidth()){
     left = leftView.getMeasuredWidth();
    }


   }

   return left;
  }

8、手松開時重寫onViewReleased方法,實現(xiàn)滑動手松開時,rightView是打開還是關閉

    1.使用ViewDragHelper滑動時,要調用invalidate方法,回調computeScroll方法
    2.重寫computeScroll方法

        1).先判斷是否要繼承滑動

        2).使用兼容的invalidate方法來實現(xiàn)勻速滑動

  @Override
  public void onViewReleased(View releasedChild, float xvel, float yvel) {

   //松開后,什么時候打開rightView,什么時候關閉leftView
   //臨界值,rightView.getLeft() 和 屏幕的寬度-rightView.getWidth()/2
   if(releasedChild == leftView){
    if(rightView.getLeft() < getMeasuredWidth() - rightView.getMeasuredWidth()/2){
     //使用ViewDragHelper來滑動
     helper.smoothSlideViewTo(rightView,getMeasuredWidth()-rightView.getMeasuredWidth(),0);

     invalidate();
    }else{
     helper.smoothSlideViewTo(rightView,getMeasuredWidth(),0);
     invalidate();
    }
   }

  }



 //需要重寫computeScroll

 @Override
 public void computeScroll() {
  //判斷是否要繼承滑動
  if(helper.continueSettling(true)){
   //invalidate();
   //兼容使用
   ViewCompat.postInvalidateOnAnimation(this);
  }
 }

9、實現(xiàn)刪除rightView的點擊刪除事件

    1.在listView的adapter中找到右側的rightView
    2.調用rightView的點擊事件
    3.刪除該條目

        1)刪除集合中的數(shù)據(jù)
            list.remove(position);
        2)更新adapter
            notifyDataSetChanged();
        3)重新繪制整個條目
            requestLayout();

  //設置刪除的點擊事件
  vh.delete.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    //刪除當前的數(shù)據(jù)
    list.remove(position);
    notifyDataSetChanged();

    //讓父容器更新下

   }
  });

  vh.container.requestLayout();

注意事項

1、在重寫onLayout方法的時候,給rightView設置布局的時候,寫成leftView一直出錯
2、在onTouchEvent中要返回true,因為要消費該事件
3、在使用ViewDragHelper.Callback時,重寫tryCaptureView時要返回true
4、在onTouchEvent中,不使用scrollby或者scrollTo,而是使用ViewDragHelper工具類,不需要判斷滑動的距離

總結

1、首先該控件是自定義View,不是組合控件,因為組合的話rightView在屏幕右側不能實現(xiàn)
2、是自定義View中的繼承ViewGroup,因為左側leftView和右側rightView都是TextView不需要自己畫

源碼

SlideDelete的源碼

package com.example.movedelete;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by guixin on 2017/1/5.
 */

public class SlideDelete extends ViewGroup {

 private View leftView;
 private View rightView;
 private ViewDragHelper helper;



 //第一步關聯(lián)構造方法
 //第二步重寫onMeasure和onLViewayout測量子View和布局子View


 public SlideDelete(Context context) {
  this(context,null);
 }

 public SlideDelete(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }

 public SlideDelete(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);

  helper = ViewDragHelper.create(this, callback);

 }

 private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
  //手勢滑動時
  @Override
  public boolean tryCaptureView(View child, int pointerId) {
   return true;
  }


  //拖動控件水平移動
  @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){
    //只處理右邊的越界問題,因為左側越界的時看不到該View
    if(left <= leftView.getMeasuredWidth()- rightView.getMeasuredWidth()){
     left = leftView.getMeasuredWidth()- rightView.getMeasuredWidth();
    }else if(left >= leftView.getMeasuredWidth()){
     left = leftView.getMeasuredWidth();
    }


   }

   return left;
  }


  //監(jiān)聽控件移動狀態(tài)
  @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);
   }


  }

  //解決滑動一半松手時,View的復位

  /**
   *
   * @param releasedChild 松開的View
   * @param xvel
   * @param yvel
   */
  @Override
  public void onViewReleased(View releasedChild, float xvel, float yvel) {

   //松開后,什么時候打開rightView,什么時候關閉leftView
   //臨界值,rightView.getLeft() 和 屏幕的寬度-rightView.getWidth()/2
   if(releasedChild == leftView){
    if(rightView.getLeft() < getMeasuredWidth() - rightView.getMeasuredWidth()/2){
     //使用ViewDragHelper來滑動
     helper.smoothSlideViewTo(rightView,getMeasuredWidth()-rightView.getMeasuredWidth(),0);

     invalidate();
    }else{
     helper.smoothSlideViewTo(rightView,getMeasuredWidth(),0);
     invalidate();
    }
   }

  }
 };

 //需要重寫computeScroll

 @Override
 public void computeScroll() {
  //判斷是否要繼承滑動
  if(helper.continueSettling(true)){
   //invalidate();
   //兼容使用
   ViewCompat.postInvalidateOnAnimation(this);
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  //對當前組合View的測量,不使用的話,也可以自己設置
  measureChildren(widthMeasureSpec,heightMeasureSpec);
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);



 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  //第一步獲取里面子View
  leftView = getChildAt(0);
  rightView = getChildAt(1);
  //第二步給子View提供相應的布局
  int leftL = 0;
  int leftT = 0;
  int leftR = leftView.getMeasuredWidth();
  int leftB = leftView.getMeasuredHeight();
  leftView.layout(leftL,leftT,leftR,leftB);

  //給rightView提供相應的布局
  int rightL = leftView.getMeasuredWidth();
  int rightT = 0;
  int rightR = leftView.getMeasuredWidth()+ rightView.getMeasuredWidth();
  int rightB = rightView.getMeasuredHeight();
  rightView.layout(rightL,rightT,rightR,rightB);

 }

 //View的事件傳遞

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //1,要消費該事件,所以直接返回true
  //2,使用ViewDragHelper來實現(xiàn)滑動效果
  helper.processTouchEvent(event);
  return true;
 }
}

MainActivity.java源碼

package com.example.movedelete;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import com.example.movedelete.adapter.SlideDeleteAdapter;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

 private ListView lv;
 private ArrayList<String> list;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  //初始化視圖
  initView();
  //初始化數(shù)據(jù)
  initData();
  //初始化事件
  initEvent();


 }

 //初始化視圖
 private void initView() {
  lv = (ListView) findViewById(R.id.lv);
 }

 //初始化數(shù)據(jù)
 private void initData() {
  list = new ArrayList<>();
  for (int i = 0; i < 20; i++) {
   list.add("第"+i+"項條目");
  }
 }

 //初始化事件
 private void initEvent() {
  SlideDeleteAdapter adapter = new SlideDeleteAdapter(list);
  lv.setAdapter(adapter);

 }
}

SlideDeleteAdapter.java源碼

package com.example.movedelete.adapter;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.movedelete.R;
import com.example.movedelete.SlideDelete;

import java.util.ArrayList;

/**
 * Created by guixin on 2017/1/5.
 */
public class SlideDeleteAdapter extends BaseAdapter{
 private ArrayList<String> list;

 public SlideDeleteAdapter(ArrayList<String> list) {
  this.list = list;
 }

 @Override
 public int getCount() {
  return list == null &#63; 0 : list.size();
 }

 @Override
 public String getItem(int position) {
  return list == null &#63; null : list.get(position);
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(final int position, View convertView, ViewGroup parent) {
  ViewHolder vh;
  if(convertView == null){
   convertView = View.inflate(parent.getContext(), R.layout.item_slide,null);
   vh = new ViewHolder(convertView);

   convertView.setTag(vh);
  }else{
   vh = (ViewHolder) convertView.getTag();
  }

  vh.content.setText(list.get(position));

  //設置刪除的點擊事件
  vh.delete.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    //刪除當前的數(shù)據(jù)
    list.remove(position);
    notifyDataSetChanged();

    //讓父容器更新下

   }
  });

  vh.container.requestLayout();

  return convertView;
 }

 class ViewHolder{
  private TextView content;
  private TextView delete;
  private SlideDelete container;

  public ViewHolder(View v){
    container = (SlideDelete) v.findViewById(R.id.container);
   content = (TextView) v.findViewById(R.id.content);
    delete = (TextView) v.findViewById(R.id.delete);
  }
 }

}

activity_main.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/activity_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <ListView
  android:id="@+id/lv"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

 </ListView>



</RelativeLayout>

item_slide.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="match_parent"
 android:layout_height="match_parent">
 <com.example.movedelete.SlideDelete
  android:id="@+id/container"
  android:layout_width="match_parent"
  android:layout_height="80dp">

  <TextView

   android:id="@+id/content"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center"
   android:background="#33000000"
   android:text="第0個條目"
   android:textColor="#fff"
   android:textSize="20sp" />
  <TextView

   android:id="@+id/delete"
   android:layout_width="80dp"
   android:layout_height="match_parent"
   android:background="#f00"
   android:gravity="center"
   android:text="刪除"
   android:textColor="#fff"
   android:textSize="20sp" />

 </com.example.movedelete.SlideDelete>

</LinearLayout>

關于怎么在android中使用View實現(xiàn)一個滑動刪除效果就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI