Android 14 修改侧滑手势动画效果

涉及关键类

SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java

SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt

修改如下:

一,覆盖系统的默认手势效果

SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt

Kotlin 复制代码
//start add code
private var slideBackView: SlideBackView? = null
//end add code

override fun setLayoutParams(layoutParams: WindowManager.LayoutParams) {
    this.layoutParams = layoutParams
    //start add code
    slideBackView = SlideBackView(context, miShadeController)
    windowManager.addView(slideBackView, layoutParams)
    //end add code
}
Kotlin 复制代码
override fun onMotionEvent(event: MotionEvent) {
    //start add code
    if (slideBackView?.onTouchEventList(event) == true) return
    //end add code

   。。。。
}

二、实现手势动画效果

SlideBackView.java 手势动画效果

java 复制代码
package com.android.systemui.navigationbar.gestural;


import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.Arrays;
import java.util.List;

public class SlideBackView extends View {

    private static final int UN = -1;
    private static final int LEFT = 0;
    private static final int RIGHT = 1;

    private static final int MAX_WIDTH = 60;

    private static final int THRESHOLD = 50;
    private float startX = 0f;
    private float downX = 0f;
    private float moveX = 0f;
    private float moveY = 0f;
    private float upX = 0f;

    private float distanceX = 0f;

    private float speed = 0.5f;

    private int showType = UN;
    Path cubicPath;
    Paint wavePaint;
    private ValueAnimator valueAnimator;
    private Path arrowPath;
    private Paint arrowPaint;
    private static final int ARROW_SIZE = 8;
    private static final int SLIDE_HEIGHT = 400;
    private  MiShadeController controller;

    public SlideBackView(Context context, MiShadeController  controller) {
        this(context, null,controller);
    }

    public SlideBackView(Context context, AttributeSet attrs, MiShadeController  controller) {
        super(context, attrs);
        this.controller=controller;
        init();
    }

    private void init() {
        cubicPath = new Path();
        arrowPath = new Path();
        wavePaint = new Paint();
        wavePaint.setColor(0x11000000);
        wavePaint.setAntiAlias(true); // 启用抗锯齿

        arrowPaint = new Paint();
        arrowPaint.setColor(Color.WHITE);
        arrowPaint.setStyle(Paint.Style.STROKE);
        arrowPaint.setAntiAlias(true); // 启用抗锯齿
        arrowPaint.setStrokeWidth(2);

        valueAnimator = ObjectAnimator.ofFloat(1, 0);
        valueAnimator.setDuration(500);
        valueAnimator.addUpdateListener(animation -> {
            distanceX = distanceX * (Float) animation.getAnimatedValue();
            postInvalidate();
        });
    }


    private boolean isReachThreshold() {
        return startX < THRESHOLD || startX > getMeasuredWidth() - THRESHOLD;
    }

    private void initSlideDirection() {
        if (startX < THRESHOLD) {
            showType = LEFT;
        } else if (startX > getMeasuredWidth() - THRESHOLD) {
            showType = RIGHT;
        } else {
            showType = UN;
        }
    }
    private boolean isHideBackView = false;

    public  boolean onTouchEventList(MotionEvent event){
        if (valueAnimator.isRunning()) return false;
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            startX = downX = event.getX();
            if (!isReachThreshold()) {
                showType = UN;
                return false;
            }
            initSlideDirection();
        } else if (action == MotionEvent.ACTION_MOVE) {
            if (!isReachThreshold()) {
                showType = UN;
                return false;
            }
            moveX = event.getX();
            moveY = event.getY();
            distanceX = moveX - downX;
            postInvalidate();
        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
            if (!isReachThreshold()) {
                showType = UN;
                return false;
            }
            upX = event.getX();
            distanceX = upX - downX;
            handUpEvent();
        }
        return false;
    }

    private void handUpEvent() {
        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }
        valueAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (showType == UN) return;

        // draw wave
        cubicPath.reset();

        int currentY = (int) Math.min(Math.max(SLIDE_HEIGHT/2f,moveY),getHeight()-SLIDE_HEIGHT/2f);

        // 凸起上部Y
        int topY = (int) (currentY - SLIDE_HEIGHT/2F);
        // 凸起下部Y
        int bottomY = (int) (currentY + SLIDE_HEIGHT/2F);
        // 凸起底部X
        int footX = showType == LEFT ? 0 : getWidth();
        // 凸起顶部X
        int peekX;
        if (showType == LEFT) {
            peekX = (int) (footX + Math.min(distanceX * speed, MAX_WIDTH));
        } else {
            peekX = (int) (footX - Math.min(Math.abs(distanceX) * speed, MAX_WIDTH));
        }

        int x1 = footX;
        int y1 = (int) (topY + SLIDE_HEIGHT*0.2F);

        int x2 = peekX;
        int y2 = (int) (topY + SLIDE_HEIGHT*0.3F);

        int x4 = peekX;
        int y4 = (int) (bottomY - SLIDE_HEIGHT*0.3F);

        int x5 = footX;
        int y5 = (int) (bottomY - SLIDE_HEIGHT*0.2F);

        cubicPath.moveTo(footX, topY);
        cubicPath.cubicTo(x1, y1, x2, y2, peekX, currentY);
        cubicPath.cubicTo(x4, y4, x5, y5, footX, bottomY);
        cubicPath.close();
        wavePaint.setAlpha((int) (Math.abs(distanceX) / MAX_WIDTH * 64));
        canvas.drawPath(cubicPath, wavePaint);

        arrowPath.reset();
        if (showType == LEFT) {
            float centerX = Math.min(distanceX * speed, MAX_WIDTH)/2F - 10;
            arrowPath.moveTo(centerX+ARROW_SIZE , currentY - ARROW_SIZE);
            arrowPath.lineTo(centerX, currentY);
            arrowPath.lineTo(centerX+ ARROW_SIZE , currentY + ARROW_SIZE);
        } else {
            float centerX = peekX+Math.min(Math.abs(distanceX) * speed, MAX_WIDTH)/2F + 6;
            arrowPath.moveTo(centerX + ARROW_SIZE, currentY - ARROW_SIZE);
            arrowPath.lineTo(centerX, currentY);
            arrowPath.lineTo(centerX + ARROW_SIZE, currentY + ARROW_SIZE);
        }
        canvas.drawPath(arrowPath, arrowPaint);
    }

 
 
}

是不是很简单,但是很多兄弟看了很多文章 找了很多资料却始终找不到具体的修改位置,看我的一篇就够了 觉得我写的好的兄弟帮忙点个赞!!谢谢

相关推荐
Digitally1 小时前
如何将文件从 iPhone 传输到 Android(新指南)
android·ios·iphone
whysqwhw2 小时前
OkHttp深度架构缺陷分析与演进规划
android
用户7093722538512 小时前
Android14 SystemUI NotificationShadeWindowView 加载显示过程
android
木叶丸2 小时前
跨平台方案该如何选择?
android·前端·ios
顾林海3 小时前
Android ClassLoader加载机制详解
android·面试·源码
用户2018792831673 小时前
🎨 童话:Android画布王国的奇妙冒险
android
whysqwhw4 小时前
OkHttp框架的全面深入架构分析
android
你过来啊你4 小时前
Android App冷启动流程详解
android
泓博4 小时前
KMP(Kotlin Multiplatform)改造(Android/iOS)老项目
android·ios·kotlin
移动开发者1号5 小时前
使用Baseline Profile提升Android应用启动速度的终极指南
android·kotlin