类似ios滑动开关

效果图:


一、attrs的xml文件自定义属性:

shape设置开关的形状分别是矩形、圆形。

<!--自定义开关属性-->
<declare-styleable name="slideswitch">
    <attr name="themeColor" format="color" />
    <attr name="isOpen" format="boolean" />
    <attr name="shape">
        <enum name="rect" value="1" />
        <enum name="circle" value="2" />
    </attr>
</declare-styleable>
二、自定义开关控件:

package testslideswitch.testslideswitch.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

import testslideswitch.testslideswitch.R;

public class SlideSwitch extends View {

   public static final int SHAPE_RECT = 1;
   public static final int SHAPE_CIRCLE = 2;
   private static final int RIM_SIZE = 6;
   private static final int DEFAULT_COLOR_THEME = Color.parseColor("#ff00ee00");
   // 3 attributes
   private int color_theme;
   private boolean isOpen;
   private int shape;
   // varials of drawing
   private Paint paint;
   private Rect backRect;
   private Rect frontRect;
   private RectF frontCircleRect;
   private RectF backCircleRect;
   private int alpha;
   private int max_left;
   private int min_left;
   private int frontRect_left;
   private int frontRect_left_begin = RIM_SIZE;
   private int eventStartX;
   private int eventLastX;
   private int diffX = 0;
   private boolean slideable = true;
   private SlideListener listener;

   public interface SlideListener {
      public void open();

      public void close();
   }

   public SlideSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      listener = null;
      paint = new Paint();
      paint.setAntiAlias(true);
      TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.slideswitch);
      color_theme = a.getColor(R.styleable.slideswitch_themeColor,
            DEFAULT_COLOR_THEME);
      isOpen = a.getBoolean(R.styleable.slideswitch_isOpen, false);
      shape = a.getInt(R.styleable.slideswitch_shape, SHAPE_RECT);
      a.recycle();
   }

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

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

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      int width = measureDimension(280, widthMeasureSpec);
      int height = measureDimension(140, heightMeasureSpec);
      if (shape == SHAPE_CIRCLE) {
         if (width < height)
            width = height * 2;
      }
      setMeasuredDimension(width, height);
      initDrawingVal();
   }

   public void initDrawingVal() {
      int width = getMeasuredWidth();
      int height = getMeasuredHeight();

      backCircleRect = new RectF();
      frontCircleRect = new RectF();
      frontRect = new Rect();
      backRect = new Rect(0, 0, width, height);
      min_left = RIM_SIZE;
      if (shape == SHAPE_RECT)
         max_left = width / 2;
      else
         max_left = width - (height - 2 * RIM_SIZE) - RIM_SIZE;
      if (isOpen) {
         frontRect_left = max_left;
         alpha = 255;
      } else {
         frontRect_left = RIM_SIZE;
         alpha = 0;
      }
      frontRect_left_begin = frontRect_left;
   }

   public int measureDimension(int defaultSize, int measureSpec) {
      int result;
      int specMode = MeasureSpec.getMode(measureSpec);
      int specSize = MeasureSpec.getSize(measureSpec);
      if (specMode == MeasureSpec.EXACTLY) {
         result = specSize;
      } else {
         result = defaultSize; // UNSPECIFIED
         if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
         }
      }
      return result;
   }

   @Override
   protected void onDraw(Canvas canvas) {
      if (shape == SHAPE_RECT) {
         paint.setColor(Color.GRAY);
         canvas.drawRect(backRect, paint);
         paint.setColor(color_theme);
         paint.setAlpha(alpha);
         canvas.drawRect(backRect, paint);
         frontRect.set(frontRect_left, RIM_SIZE, frontRect_left
               + getMeasuredWidth() / 2 - RIM_SIZE, getMeasuredHeight()
               - RIM_SIZE);
         paint.setColor(Color.WHITE);
         canvas.drawRect(frontRect, paint);
      } else {
         // draw circle
         int radius;
         radius = backRect.height() / 2 - RIM_SIZE;
         paint.setColor(Color.GRAY);
         backCircleRect.set(backRect);
         canvas.drawRoundRect(backCircleRect, radius, radius, paint);
         paint.setColor(color_theme);
         paint.setAlpha(alpha);
         canvas.drawRoundRect(backCircleRect, radius, radius, paint);
         frontRect.set(frontRect_left, RIM_SIZE, frontRect_left
               + backRect.height() - 2 * RIM_SIZE, backRect.height()
               - RIM_SIZE);
         frontCircleRect.set(frontRect);
         paint.setColor(Color.WHITE);
         canvas.drawRoundRect(frontCircleRect, radius, radius, paint);
      }
   }
   
   @Override
   public boolean onTouchEvent(MotionEvent event) {
      if (slideable == false)
         return super.onTouchEvent(event);
      int action = MotionEventCompat.getActionMasked(event);
      switch (action) {
      case MotionEvent.ACTION_DOWN:
         eventStartX = (int) event.getRawX();
         break;
      case MotionEvent.ACTION_MOVE:
         eventLastX = (int) event.getRawX();
         diffX = eventLastX - eventStartX;
         int tempX = diffX + frontRect_left_begin;
         tempX = (tempX > max_left ? max_left : tempX);
         tempX = (tempX < min_left ? min_left : tempX);
         if (tempX >= min_left && tempX <= max_left) {
            frontRect_left = tempX;
            alpha = (int) (255 * (float) tempX / (float) max_left);
            invalidateView();
         }
         break;
      case MotionEvent.ACTION_UP:
         int wholeX = (int) (event.getRawX() - eventStartX);
         frontRect_left_begin = frontRect_left;
         boolean toRight;
         toRight = (frontRect_left_begin > max_left / 2 ? true : false);
         if (Math.abs(wholeX) < 3) {
            toRight = !toRight;
         }
         moveToDest(toRight);
         break;
      default:
         break;
      }
      return true;
   }

   /**
    * draw again
    */
   private void invalidateView() {
      if (Looper.getMainLooper() == Looper.myLooper()) {
         invalidate();
      } else {
         postInvalidate();
      }
   }

   public void setSlideListener(SlideListener listener) {
      this.listener = listener;
   }

   @TargetApi(Build.VERSION_CODES.HONEYCOMB)
   public void moveToDest(final boolean toRight) {
      ValueAnimator toDestAnim = ValueAnimator.ofInt(frontRect_left,
            toRight ? max_left : min_left);
      toDestAnim.setDuration(500);
      toDestAnim.setInterpolator(new AccelerateDecelerateInterpolator());
      toDestAnim.start();
      toDestAnim.addUpdateListener(new AnimatorUpdateListener() {

         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
            frontRect_left = (Integer) animation.getAnimatedValue();
            alpha = (int) (255 * (float) frontRect_left / (float) max_left);
            invalidateView();
         }
      });
      toDestAnim.addListener(new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
            if (toRight) {
               isOpen = true;
               if (listener != null)
                  listener.open();
               frontRect_left_begin = max_left;
            } else {
               isOpen = false;
               if (listener != null)
                  listener.close();
               frontRect_left_begin = min_left;
            }
         }
      });
   }

   /**
    * 设置状态
    * <h3>Version</h3> 1.0
    * <h3>CreateTime</h3> 2016/3/8,9:40
    * <h3>UpdateTime</h3> 2016/3/8,9:40
    * <h3>CreateAuthor</h3> lzb
    * <h3>UpdateAuthor</h3>
    * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
    *
    * @param isOpen true 开关处于打开状态,否则处于关闭状态
    */
   public void setState(boolean isOpen) {
      this.isOpen = isOpen;
      initDrawingVal();
      invalidateView();
      if (listener != null)
         if (isOpen == true) {
            listener.open();
         } else {
            listener.close();
         }
   }

   public void setShapeType(int shapeType) {
      this.shape = shapeType;
   }

   /**
    * 设置滑动状态
    * <h3>Version</h3> 1.0
    * <h3>CreateTime</h3> 2016/3/8,9:41
    * <h3>UpdateTime</h3> 2016/3/8,9:41
    * <h3>CreateAuthor</h3> lzb
    * <h3>UpdateAuthor</h3>
    * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
    *
    * @param slideable true 能够滑动,否则不能滑动
    */
   public void setSlideable(boolean slideable) {
      this.slideable = slideable;
   }

   @Override
   protected void onRestoreInstanceState(Parcelable state) {
      if (state instanceof Bundle) {
         Bundle bundle = (Bundle) state;
         this.isOpen = bundle.getBoolean("isOpen");
         state = bundle.getParcelable("instanceState");
      }
      super.onRestoreInstanceState(state);
   }

   @Override
   protected Parcelable onSaveInstanceState() {
      Bundle bundle = new Bundle();
      bundle.putParcelable("instanceState", super.onSaveInstanceState());
      bundle.putBoolean("isOpen", this.isOpen);
      return bundle;
   }
}
三、xml中使用:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:slideswitch="http://schemas.android.com/apk/res-auto"
    android:background="#ffffffff"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="10dip"
    tools:context="com.example.testlibs.MainActivity">

    <testslideswitch.testslideswitch.widget.SlideSwitch
        android:id="@+id/swit"
        android:layout_width="150dip"
        android:layout_height="60dip"
        slideswitch:isOpen="true"
        slideswitch:shape="circle"
        slideswitch:themeColor="#ffee3a00" >
    </testslideswitch.testslideswitch.widget.SlideSwitch>

    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <testslideswitch.testslideswitch.widget.SlideSwitch
        android:id="@+id/swit2"
        android:layout_width="190dip"
        android:layout_height="100dip"
        android:layout_marginTop="10dip"
        slideswitch:isOpen="true"
        slideswitch:shape="circle"
        slideswitch:themeColor="#ff0a5a00" >
    </testslideswitch.testslideswitch.widget.SlideSwitch>

    <testslideswitch.testslideswitch.widget.SlideSwitch
        android:id="@+id/swit3"
        android:layout_width="60dip"
        android:layout_height="30dip"
        android:layout_marginTop="10dip"
        slideswitch:isOpen="true"
        slideswitch:shape="circle"
        slideswitch:themeColor="#ff73aa00" >
    </testslideswitch.testslideswitch.widget.SlideSwitch>

    <testslideswitch.testslideswitch.widget.SlideSwitch
        android:id="@+id/swit4"
        android:layout_width="100dip"
        android:layout_height="120dip"
        android:layout_marginTop="10dip"
        slideswitch:isOpen="false"
        slideswitch:shape="circle"
        slideswitch:themeColor="#f200aa96" >
    </testslideswitch.testslideswitch.widget.SlideSwitch>

    <testslideswitch.testslideswitch.widget.SlideSwitch
        android:id="@+id/swit5"
        android:layout_width="90dip"
        android:layout_height="50dip"
        android:layout_marginTop="10dip"
        slideswitch:isOpen="true"
        slideswitch:shape="rect"
        slideswitch:themeColor="#f23331a0" >
    </testslideswitch.testslideswitch.widget.SlideSwitch>

</LinearLayout>
四、Activity中使用:

public class MainActivity extends Activity implements SlideSwitch.SlideListener {

   TextView txt;
   SlideSwitch slide;
   SlideSwitch slide2;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      slide = (SlideSwitch) findViewById(R.id.swit);
      slide2 = (SlideSwitch) findViewById(R.id.swit2);
      slide.setState(true);
      txt = (TextView) findViewById(R.id.txt);
      slide.setSlideListener(this);
   }

   @Override
   public void open() {
      // TODO Auto-generated method stub
      txt.setText("first switch is opend, and set the second one is 'slideable'");
      slide2.setSlideable(true);
   }

   @Override
   public void close() {
      // TODO Auto-generated method stub
      txt.setText("first switch is closed,and set the second one is 'unslideable'");
      slide2.setSlideable(false);
   }
}











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RecyclerView是Android的一个重要控件,它通常用于展示大量数据,能够随着用户的手势滑动和操作响应式变化。不过,RecyclerView在滑动删除方面与iOS相比,缺乏类似的功能,这就需要我们通过自己的代码来实现仿照iOS滑动删除功能。 首先,我们需要添加一个ItemTouchHelper.Callback回调类来捕捉RecyclerView上的用户手势。它将侦听用户手势,比如拖动和滑动删除,并提供相应的操作回调。实现滑动删除的方法与操作步骤如下: 1. 实现 ItemTouchHelper.Callback 类 public class SwipeToDeleteCallback extends ItemTouchHelper.Callback { private final MyAdapter mAdapter; public SwipeToDeleteCallback(MyAdapter adapter) { mAdapter = adapter; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(0, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { // do nothing return false; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); mAdapter.deleteItem(position); } } 2. 给RecyclerView添加ItemTouchHelper ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(adapter)); itemTouchHelper.attachToRecyclerView(rv); 3. 在 adapter 中添加删除操作 public void deleteItem(int position) { itemList.remove(position); notifyItemRemoved(position); } 这样就可以完美实现RecyclerView的仿照iOS滑动删除功能了。在这个过程中,我们需要注意一些细节问题。比如,当用户从右向左滑动时,我们应该使用ItemTouchHelper.START;当用户从左向右滑动时,我们应该使用ItemTouchHelper.END。我们还需要在adapter中编写适当的逻辑代码来删除条目和更新视图。总的来说,RecyclerView是一个相当强大和灵活的控件,可以根据我们的需要自定义和实现各种各样的效果和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值