Android 侧边滑动关闭Activity的示例代码

所属分类: 软件编程 / Android 阅读数: 101
收藏 0 赞 0 分享

0.效果图

1.设置Activity样式属性

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowIsTranslucent">true</item>
</style>

2.自定义侧边阴影视图

class SlideBackView extends View {

    private Paint mBgPaint, mShadowPaint;
    private RectF mBgRectF, mShadowRectF;
    private float mRatio;
    private float mShadowSize;

    public SlideBackView(Context context) {
      super(context);
      mBgPaint = new Paint();
      mBgPaint.setAntiAlias(true);
      mBgPaint.setColor(0xff000000);
      mShadowPaint = new Paint();
      mShadowPaint.setAntiAlias(true);
      mShadowPaint.setStyle(Paint.Style.FILL);
      mShadowSize = dp2px(15);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      mBgRectF = new RectF();
      mBgRectF.top = 0;
      mBgRectF.left = 0;
      mBgRectF.bottom = MeasureSpec.getSize(heightMeasureSpec);

      mShadowRectF = new RectF();
      mShadowRectF.top = 0;
      mShadowRectF.bottom = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      int width = getMeasuredWidth();
      float right = mRatio * width;
      mBgRectF.right = right;
      mBgPaint.setAlpha((int) (128 * (1 - mRatio)));
      canvas.drawRect(mBgRectF, mBgPaint);
      mShadowRectF.left = right - mShadowSize;
      mShadowRectF.right = right;
      mShadowPaint.setShader(new LinearGradient(mShadowRectF.left, 0, mShadowRectF.right, 0, 0x00000000, 0x26000000, Shader.TileMode.CLAMP));
      canvas.drawRect(mShadowRectF, mShadowPaint);
    }

    public void setDistance(float ratio) {
      mRatio = ratio;
      invalidate();
    }

    private float dp2px(float dpValue) {
      float density = getResources().getDisplayMetrics().density;
      return dpValue * density + 0.5F;
    }
  }

3.定义可滑动的Activity父类

public class SlideBaseActivity extends AppCompatActivity implements ValueAnimator.AnimatorUpdateListener {

  private boolean isAnimate, isSlide, isHandle;
  private float moveNum;
  private float lastX, lastY;
  private int lastPointerCount;
  private float mAnimatedValue;
  private ValueAnimator mValueAnimator;
  private SlideBackView mSlideBackView;
  private float mTouchSlop;
  private List<ShieldView> shieldViews = new ArrayList<>();

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    super.onCreate(savedInstanceState);
    initAnimator();
    initSlideBackView();
    mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
  }

  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    mAnimatedValue = (float) animation.getAnimatedValue();
    moveView(mAnimatedValue);
  }

  @Override
  public boolean dispatchTouchEvent(MotionEvent event) {
    if (!isAnimate) {
      float x = event.getRawX();
      float y = event.getRawY();
      if (event.getPointerCount() != lastPointerCount) {
        lastPointerCount = event.getPointerCount();
        lastX = x;
        lastY = y;
      }
      float offsetX, offsetY;
      switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE:
          offsetX = x - lastX;
          offsetY = y - lastY;
          if (!isHandle) {
            float absX = Math.abs(offsetX);
            float absY = Math.abs(offsetY);
            if (absX > mTouchSlop) {
              if (absX * 0.5f > absY) {
                isSlide = true;
                checkSlide((int) x, (int) y);
              } else {
                isSlide = false;
              }
              isHandle = true;
            }
          } else if (isSlide) {
            moveNum += offsetX;
            if (moveNum < 0) {
              moveNum = 0;
            }
            moveView(moveNum);
            lastX = event.getX();
          }
          break;
        case MotionEvent.ACTION_UP:
          if (isHandle) {
            isSlide = false;
            isHandle = false;
            isAnimate = true;
            int width = getWindow().getDecorView().getMeasuredWidth();
            if (moveNum < width / 3f) {
              mValueAnimator.setFloatValues(moveNum, 0);
            } else {
              mValueAnimator.setFloatValues(moveNum, width);
            }
            mValueAnimator.start();
            moveNum = 0;
            lastPointerCount = 0;
          }
      }
    }
    return isSlide || super.dispatchTouchEvent(event);
  }

  /**
   * 添加禁用滑动的子布局
   */
  public void addShieldView(View view) {
    shieldViews.add(new ShieldView(false, view));
  }

  /**
   * 添加水平禁用滑动的子布局
   */
  public void addHorizontalShieldView(View view) {
    shieldViews.add(new ShieldView(true, view));
  }

  /**
   * 移除禁用滑动的子布局
   */
  public void removeShieldView(View view) {
    for (ShieldView v : shieldViews) {
      if (v.view != null && v.view.equals(view)) {
        shieldViews.remove(v);
        break;
      }
    }
  }

  /**
   * 清空禁用滑动的子布局
   */
  public void clearShieldView() {
    shieldViews.clear();
  }

  private void initAnimator() {
    mValueAnimator = new ValueAnimator();
    mValueAnimator.setDuration(300);
    mValueAnimator.addUpdateListener(this);
    mValueAnimator.addListener(new AnimatorListenerAdapter() {
      @Override
      public void onAnimationEnd(Animator animation) {
        isAnimate = false;
        if (mAnimatedValue == getWindow().getDecorView().getMeasuredWidth()) {
          SlideBaseActivity.super.finish();
          overridePendingTransition(0, 0);
        }
      }
    });
  }

  private void initSlideBackView() {
    mSlideBackView = new SlideBackView(this);
    ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
    decorView.addView(mSlideBackView);
  }

  private void moveView(float moveX) {
    ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
    mSlideBackView.setDistance(moveX / decorView.getMeasuredWidth());
    int count = decorView.getChildCount();
    for (int i = 0; i < count; i++) {
      View view = decorView.getChildAt(i);
      if (view != mSlideBackView) {
        view.setX(moveX);
      }
    }
  }

  private void checkSlide(int x, int y) {
    for (ShieldView v : shieldViews) {
      Rect rect = new Rect();
      v.view.getGlobalVisibleRect(rect);
      if (rect.contains(x, y) && (!(lastX < x && !v.view.canScrollHorizontally(-1)) || (!v.isHorizontal))) {
        isSlide = false;
      }
    }
  }
  
  class ShieldView {
    boolean isHorizontal;
    View view;

    public ShieldView(boolean isHorizontal, View view) {
      this.isHorizontal = isHorizontal;
      this.view = view;
    }
  }
}

4.使用

继承SlideBaseActivity类,可调用addShieldViewaddHorizontalShieldView方法解决事件冲突。

5.项目源码

https://gitee.com/yugu/slide-demo

更多精彩内容其他人还在看

Android网络编程之获取网络上的Json数据实例

这篇文章主要介绍了Android网络编程之获取网络上的Json数据实例,本文用完整的代码实例讲解了在Android中读取网络中Json数据的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中的windowSoftInputMode属性详解

这篇文章主要介绍了Android中的windowSoftInputMode属性详解,本文对windowSoftInputMode的9个属性做了详细总结,需要的朋友可以参考下
收藏 0 赞 0 分享

Android网络编程之UDP通信模型实例

这篇文章主要介绍了Android网络编程之UDP通信模型实例,本文给出了服务端代码和客户端代码,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中使用ListView实现漂亮的表格效果

这篇文章主要介绍了Android中使用ListView实现漂亮的表格效果,本文用详细的代码实例创建了一个股票行情表格,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中刷新界面的二种方法

这篇文章主要介绍了Android中刷新界面的二种方法,本文使用Handler、postInvalidate两种方法实现界面刷新,需要的朋友可以参考下
收藏 0 赞 0 分享

Android SDK三种更新失败及其解决方法

这篇文章主要介绍了Android SDK三种更新失败及其解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(一)

Android3.0(API level 11)开始,Android设备不再需要专门的菜单键。随着这种变化,Android app应该取消对传统6项菜单的依赖。取而代之的是提供anction bar来提供基本的用户功能
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(二)

这次将继续上一篇文章没有讲完的Menu的学习,上下文菜单(Context menu)和弹出菜单(Popup menu)
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(三)

今天继续昨天没有讲完的Menu的学习,主要是Popup Menu的学习,需要的朋友可以参考下
收藏 0 赞 0 分享

Android显示网络图片实例

这篇文章主要介绍了Android显示网络图片的方法,以实例形式展示了Android程序显示网络图片的方法,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多