• 应用内悬浮按钮 可吸附 展开有动画 mini播放器


    SystemUtils.java:

    public class SystemUtils {
    
        public static int getStatusBarHeight(Context context) {
            int result = 0;
            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = context.getResources().getDimensionPixelSize(resourceId);
            }
            return result;
        }
    
        public static int getScreenWidth(Context context) {
            int screenWith = -1;
            try {
                screenWith = context.getResources().getDisplayMetrics().widthPixels;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return screenWith;
        }
    
        public static int getScreenHeight(Context context) {
            int screenHeight = -1;
            try {
                screenHeight = context.getResources().getDisplayMetrics().heightPixels;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return screenHeight;
        }
    
    }

    布局文件:layout_music_floating_view.xml

    是一个头像,加三个按钮:

    效果如下:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_music_floating_view"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:layout_gravity="center"
                android:orientation="horizontal">
                <com.example.m_evolution.View.CircleImageView
                    android:id="@+id/iv_user_avatar"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:src="@drawable/user_demo"
                    android:layout_gravity="center"/>
                <LinearLayout
                    android:id="@+id/layout_more"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:orientation="horizontal">
                    <RelativeLayout
                        android:id="@+id/button_play"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:layout_gravity="center">
                        <ImageView
                            android:layout_width="20dp"
                            android:layout_height="20dp"
                            android:layout_centerInParent="true"
                            android:src="@drawable/icon_floating_view_pause"/>
                    </RelativeLayout>
                    <RelativeLayout
                        android:id="@+id/button_cut"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:layout_gravity="center">
                        <ImageView
                            android:layout_width="20dp"
                            android:layout_height="20dp"
                            android:layout_centerInParent="true"
                            android:src="@drawable/icon_floating_view_cut"/>
                    </RelativeLayout>
                    <RelativeLayout
                        android:id="@+id/button_like"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:layout_gravity="center">
                        <ImageView
                            android:layout_width="20dp"
                            android:layout_height="20dp"
                            android:layout_centerInParent="true"
                            android:src="@drawable/icon_floating_view_like"/>
                    </RelativeLayout>
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
    
    </android.support.constraint.ConstraintLayout>

     接着写一个FrameLayout来实现这个按钮,包括动画、吸附等:

    import android.animation.ValueAnimator;
    import android.content.Context;
    import android.os.Handler;
    import android.os.Looper;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.ViewGroup;
    import android.view.ViewTreeObserver;
    import android.widget.FrameLayout;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    
    import com.example.m_evolution.R;
    import com.example.m_evolution.Utils.SystemUtils;
    
    public class FloatingMagnetView extends FrameLayout {
    
        public static final int MARGIN_EDGE = 13;
        private float mOriginalRawX;
        private float mOriginalRawY;
        private float mOriginalX;
        private float mOriginalY;
        private OnListener onListener;
        private static final int TOUCH_TIME_THRESHOLD = 150;
        private long mLastTouchDownTime;
        protected MoveAnimator mMoveAnimator;
        protected int mScreenWidth;
        private int mScreenHeight;
        private int mStatusBarHeight;
    
        //View
        private CircleImageView iv_user_avatar;
        private RelativeLayout button_play;
        private RelativeLayout button_cut;
        private RelativeLayout button_like;
        private LinearLayout layout_more;
        private int width_layout_more;
        private boolean is_init_layout_more = false;
    
        private String TAG = "FloatingMagnetView";
    
        public void setOnListener(OnListener onListener) {
            this.onListener = onListener;
        }
    
        public FloatingMagnetView(Context context) {
            this(context, null);
        }
    
        public FloatingMagnetView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public FloatingMagnetView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            inflate(context, R.layout.layout_music_floating_view, this);
            iv_user_avatar = findViewById(R.id.iv_user_avatar);
            button_play = findViewById(R.id.button_play);
            button_cut = findViewById(R.id.button_cut);
            button_like = findViewById(R.id.button_like);
            layout_more = findViewById(R.id.layout_more);
            init();
        }
    
        private void init() {
            layout_more.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    // TODO Auto-generated method stub
                    if(!is_init_layout_more){
                        is_init_layout_more = true;
                        width_layout_more = layout_more.getWidth();
                        ViewGroup.LayoutParams params = layout_more.getLayoutParams();
                        params.width = 0;
                        layout_more.setLayoutParams(params);
                    }
                }
            });
            mMoveAnimator = new MoveAnimator();
            mStatusBarHeight = SystemUtils.getStatusBarHeight(getContext());
            setClickable(true);
            updateSize();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event == null) {
                return false;
            }
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    changeOriginalTouchParams(event);
                    updateSize();
                    mMoveAnimator.stop();
                    break;
                case MotionEvent.ACTION_MOVE:
                    updateViewPosition(event);
                    break;
                case MotionEvent.ACTION_UP:
                    if (isOnClickEvent(event)) {
                        int[] position = new int[2];
                        iv_user_avatar.getLocationOnScreen(position);
                        if(mOriginalRawX>=position[0] && mOriginalRawX<=position[0]+iv_user_avatar.getWidth() && mOriginalRawY>=position[1] && mOriginalRawY<=position[1]+iv_user_avatar.getHeight()){
                            final ViewGroup.LayoutParams params = layout_more.getLayoutParams();
                            if(params.width == 0){
    
                                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
                                valueAnimator.setDuration(500);
                                valueAnimator.start();//开始动画
                                //注册监听,监听属性值的变化,并设置给目标对象
                                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
                                {
                                    @Override
                                    public void onAnimationUpdate(ValueAnimator animation)
                                    {
                                        float value = (float) animation.getAnimatedValue();
                                        params.width = (int)(value*width_layout_more);
                                        layout_more.setLayoutParams(params);
    //                                    if(value == 1.0f){
                                            moveToEdge();
    //                                    }
                                    }
                                });
                            }
                            else{
                                ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0);
                                valueAnimator.setDuration(500);
                                valueAnimator.start();//开始动画
                                //注册监听,监听属性值的变化,并设置给目标对象
                                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
                                {
                                    @Override
                                    public void onAnimationUpdate(ValueAnimator animation)
                                    {
                                        float value = (float) animation.getAnimatedValue();
                                        params.width = (int)(value*width_layout_more);
                                        layout_more.setLayoutParams(params);
    //                                    if(value == 0.0f){
                                            moveToEdge();
    //                                    }
                                    }
                                });
                            }
                            return true;
                        }
                        button_play.getLocationOnScreen(position);
                        if(mOriginalRawX>=position[0] && mOriginalRawX<=position[0]+button_play.getWidth() && mOriginalRawY>=position[1] && mOriginalRawY<=position[1]+button_play.getHeight()){
                            onListener.ClickPlay();
                            return true;
                        }
                        button_cut.getLocationOnScreen(position);
                        if(mOriginalRawX>=position[0] && mOriginalRawX<=position[0]+button_cut.getWidth() && mOriginalRawY>=position[1] && mOriginalRawY<=position[1]+button_cut.getHeight()){
                            onListener.ClickCut();
                            return true;
                        }
                        button_like.getLocationOnScreen(position);
                        if(mOriginalRawX>=position[0] && mOriginalRawX<=position[0]+button_like.getWidth() && mOriginalRawY>=position[1] && mOriginalRawY<=position[1]+button_like.getHeight()){
                            onListener.ClickLike();
                            return true;
                        }
                    }
                    else{
                        moveToEdge();
                    }
                    break;
            }
            return true;
        }
    
        protected boolean isOnClickEvent(MotionEvent event) {
            if(event.getRawX() == mOriginalRawX &&event.getRawY() == mOriginalRawY){
                return (System.currentTimeMillis() - mLastTouchDownTime < TOUCH_TIME_THRESHOLD);
            }
            return false;
        }
    
        private void updateViewPosition(MotionEvent event) {
            setX(mOriginalX + event.getRawX() - mOriginalRawX);
            // 限制不可超出屏幕高度
            float desY = mOriginalY + event.getRawY() - mOriginalRawY;
            if (desY < mStatusBarHeight) {
                desY = mStatusBarHeight;
            }
            if (desY > mScreenHeight - getHeight()) {
                desY = mScreenHeight - getHeight();
            }
            setY(desY);
        }
    
        private void changeOriginalTouchParams(MotionEvent event) {
            mOriginalX = getX();
            mOriginalY = getY();
            mOriginalRawX = event.getRawX();
            mOriginalRawY = event.getRawY();
            mLastTouchDownTime = System.currentTimeMillis();
        }
    
        protected void updateSize() {
            mScreenWidth = (SystemUtils.getScreenWidth(getContext()) - this.getWidth());
            mScreenHeight = SystemUtils.getScreenHeight(getContext());
        }
    
        public void moveToEdge() {
            updateSize();
            float moveDistance = isNearestLeft() ? MARGIN_EDGE : mScreenWidth - MARGIN_EDGE;
            mMoveAnimator.start(moveDistance, getY());
        }
    
        protected boolean isNearestLeft() {
            int middle = mScreenWidth / 2;
            return getX() < middle;
        }
    
        protected class MoveAnimator implements Runnable {
    
            private Handler handler = new Handler(Looper.getMainLooper());
            private float destinationX;
            private float destinationY;
            private long startingTime;
    
            void start(float x, float y) {
                this.destinationX = x;
                this.destinationY = y;
                startingTime = System.currentTimeMillis();
                handler.post(this);
            }
    
            @Override
            public void run() {
                if (getRootView() == null || getRootView().getParent() == null) {
                    return;
                }
                float progress = Math.min(1, (System.currentTimeMillis() - startingTime) / 400f);
                float deltaX = (destinationX - getX()) * progress;
                float deltaY = (destinationY - getY()) * progress;
                move(deltaX, deltaY);
                if (progress < 1) {
                    handler.post(this);
                }
            }
    
            private void stop() {
                handler.removeCallbacks(this);
            }
        }
    
        private void move(float deltaX, float deltaY) {
            setX(getX() + deltaX);
            setY(getY() + deltaY);
        }
    
        public interface OnListener {
            void ClickPlay();
            void ClickPause();
            void ClickCut();
            void ClickLike();
        }
    
    }

    接着编写一个类来管理这个按钮:

    import android.app.Activity;
    import android.content.Context;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.v4.view.ViewCompat;
    import android.view.Gravity;
    import android.view.ViewGroup;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    
    public class MusicFloatingView{
    
        private FloatingMagnetView mEnFloatingView;
    //    private static volatile MusicFloatingView mInstance;
        private FrameLayout mContainer;
        private Context context;
    
        public MusicFloatingView(Context context) {
            this.context = context;
        }
    
    //    public static MusicFloatingView get() {
    //        return mInstance;
    //    }
    
        public MusicFloatingView remove() {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    if (mEnFloatingView == null) {
                        return;
                    }
                    if (ViewCompat.isAttachedToWindow(mEnFloatingView) && mContainer != null) {
                        mContainer.removeView(mEnFloatingView);
                    }
                    mEnFloatingView = null;
                }
            });
            return this;
        }
    
        private void ensureMiniPlayer(Context context) {
            synchronized (this) {
                if (mEnFloatingView != null) {
                    return;
                }
                mEnFloatingView = new FloatingMagnetView(context.getApplicationContext());
                mEnFloatingView.setLayoutParams(getParams());
                addViewToWindow(mEnFloatingView);
            }
        }
    
        public MusicFloatingView add() {
            ensureMiniPlayer(context);
            return this;
        }
    
        public MusicFloatingView attach(Activity activity) {
            attach(getActivityRoot(activity));
            return this;
        }
    
        public MusicFloatingView attach(FrameLayout container) {
            if (container == null || mEnFloatingView == null) {
                mContainer = container;
                return this;
            }
            if (mEnFloatingView.getParent() == container) {
                return this;
            }
            if (mContainer != null && mEnFloatingView.getParent() == mContainer) {
                mContainer.removeView(mEnFloatingView);
            }
            mContainer = container;
            、、container.addView(mEnFloatingView);
            return this;
        }
    
        public MusicFloatingView detach(Activity activity) {
            detach(getActivityRoot(activity));
            return this;
        }
    
        public MusicFloatingView detach(FrameLayout container) {
            if (mEnFloatingView != null && container != null && ViewCompat.isAttachedToWindow(mEnFloatingView)) {
                container.removeView(mEnFloatingView);
            }
            if (mContainer == container) {
                mContainer = null;
            }
            return this;
        }
    
        public FloatingMagnetView getView() {
            return mEnFloatingView;
        }
    
        public MusicFloatingView layoutParams(ViewGroup.LayoutParams params) {
            if (mEnFloatingView != null) {
                mEnFloatingView.setLayoutParams(params);
            }
            return this;
        }
    
        public MusicFloatingView setOnListener(FloatingMagnetView.OnListener onListener) {
            if (mEnFloatingView != null) {
                mEnFloatingView.setOnListener(onListener);
            }
            return this;
        }
    
        private void addViewToWindow(final FloatingMagnetView view) {
            if (mContainer == null) {
                return;
            }
            mContainer.addView(view);
        }
    
        private FrameLayout.LayoutParams getParams() {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    RelativeLayout.LayoutParams.WRAP_CONTENT,
                    RelativeLayout.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.BOTTOM | Gravity.START;
            params.setMargins(13, params.topMargin, params.rightMargin, 56);
            return params;
        }
    
        private FrameLayout getActivityRoot(Activity activity) {
            if (activity == null) {
                return null;
            }
            try {
                return (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
  • 相关阅读:
    Leetcode-Pascal's Triangle
    SRM 619
    请用漂亮欢呼-------Day38
    创建list方法总结
    [ZJOI2019]语言
    jekyll 在博客添加流程图
    jekyll 在博客添加流程图
    HttpRepl 互操作的 RESTful HTTP 服务调试命令行工具
    HttpRepl 互操作的 RESTful HTTP 服务调试命令行工具
    How to use code to exit the application in UWP
  • 原文地址:https://www.cnblogs.com/zhaozilongcjiajia/p/11227156.html
Copyright © 2020-2023  润新知