Android 仿Keep,探索向上滑動時PopupWindow向右退出消失,向下移動時PopupWindow向左推出出現

這篇文章主要是仿Keep,通過監聽ScrollView滾動事件和滾動狀態(開始、停止)來實現向上滑動時PopupWindow向右退出消失,向下移動時PopupWindow向左推出出現的功能,感覺很有趣,於是想着自己動手也實現這樣一個功能,和往常一樣,主要是想總結一下我在學習過程中的一些筆記以及需要注意的地方。

現在我們來看下項目結構圖
在這裏插入圖片描述
現在我把完整的代碼貼出來:

CustomPopupWindow

package per.juan.popupwindowdome;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;

import androidx.core.widget.NestedScrollView;

public class CustomPopupWindow extends PopupWindow {

    LinearLayout itemView;
    ImageView iv_activity_img;
    View      customView;
    View.OnClickListener mOnClickListener;
    Handler handler = new Handler();

    //是否需要顯示
    private boolean needShow=false;

    public CustomPopupWindow(Context context, CustomScrollView scrollView) {
        super(context);
        customView = LayoutInflater.from(context).inflate(R.layout.popupwin_custom, null);
        setContentView(customView);
        setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
        setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);

        itemView=customView.findViewById(R.id.itemView);
        iv_activity_img=customView.findViewById(R.id.iv_activity_img);
        setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));// 透明背景


        oa = ObjectAnimator.ofFloat(customView, "translationX", 0, getWidth() / 3 * 2);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnClickListener != null) {
                    mOnClickListener.onClick(customView);
                }
            }
        });

        scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if (scrollY > oldScrollY || scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) {
                    needShow=false;
                }
                if (scrollY < oldScrollY || scrollY == 0) {
                    needShow=true;
                }
            }
        });

        scrollView.setOnScrollListener(new CustomScrollView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(CustomScrollView view, int scrollState) {
                switch (scrollState) {
                    case SCROLL_STATE_FLING:
                        if (needShow){
                            showAnim();
                        }else{
                            hideAnim();
                        }
                        break;
                }
            }

            @Override
            public void onScroll(CustomScrollView view, boolean isTouchScroll, int l, int t, int oldl, int oldt) {
            }
        });
    }

    public void setOnClickListener(View.OnClickListener onClickListener) {
        this.mOnClickListener = onClickListener;
    }

    ObjectAnimator oa;

    public void show() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                showAtLocation(customView, Gravity.BOTTOM | Gravity.RIGHT, 0, 200);
            }
        },500);
    }

    void hideAnim() {
        ofFloat(customView.getTranslationX(), customView.getWidth());
    }

    void showAnim() {
        ofFloat(customView.getTranslationX(), 0f);
    }

    private void ofFloat(float... values) {
        oa.cancel();
        oa.setFloatValues(values);
        oa.setDuration(200);
        oa.start();
    }
}

CustomScrollView

package per.juan.popupwindowdome;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.core.widget.NestedScrollView;

/**
 * ScrollView滾動事件和滾動狀態(開始、停止)的監聽實現
 */
public class CustomScrollView extends NestedScrollView {
    private static final int CHECK_SCROLL_STOP_DELAY_MILLIS = 80;
    private static final int MSG_SCROLL = 1;

    private boolean mIsTouched = false;
    private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;

    private OnScrollListener mOnScrollListener;

    private final Handler mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {

        private int mLastY = Integer.MIN_VALUE;

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == MSG_SCROLL) {
                final int scrollY = getScrollY();
                if (!mIsTouched && mLastY == scrollY) {
                    mLastY = Integer.MIN_VALUE;
                    setScrollState(OnScrollListener.SCROLL_STATE_IDLE);
                } else {
                    mLastY = scrollY;
                    restartCheckStopTiming();
                }
                return true;
            }
            return false;
        }
    });

    private void restartCheckStopTiming() {
        mHandler.removeMessages(MSG_SCROLL);
        mHandler.sendEmptyMessageDelayed(MSG_SCROLL, CHECK_SCROLL_STOP_DELAY_MILLIS);
    }

    public CustomScrollView(Context context) {
        super(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        mOnScrollListener = onScrollListener;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        handleDownEvent(ev);
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        handleUpEvent(ev);
        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mIsTouched) {
            setScrollState(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
        } else {
            setScrollState(OnScrollListener.SCROLL_STATE_FLING);
            restartCheckStopTiming();
        }
        if (mOnScrollListener != null) {
            mOnScrollListener.onScroll(this, mIsTouched, l, t, oldl, oldt);
        }
    }

    private void handleDownEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mIsTouched = true;
                break;
        }
    }

    private void handleUpEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsTouched = false;
                restartCheckStopTiming();
                break;
        }
    }

    private void setScrollState(int state) {
        if (mScrollState != state) {
            mScrollState = state;
            if (mOnScrollListener != null) {
                mOnScrollListener.onScrollStateChanged(this, state);
            }
        }
    }

    public interface OnScrollListener {
        // 空閒狀態
        int SCROLL_STATE_IDLE = 0;
        // 觸摸滾動,手指仍在屏幕上
        int SCROLL_STATE_TOUCH_SCROLL = 1;
        // 滾動結束
        int SCROLL_STATE_FLING = 2;

        void onScrollStateChanged(CustomScrollView view, int scrollState);

        void onScroll(CustomScrollView view, boolean isTouchScroll, int l, int t, int oldl, int oldt);
    }
}

佈局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <per.juan.popupwindowdome.CustomScrollView
        android:id="@+id/nested_scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="300dp"
                android:text="底部" />
        </LinearLayout>
    </per.juan.popupwindowdome.CustomScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

使用起來還是蠻簡單的

package per.juan.popupwindowdome;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private CustomScrollView mScrollView;
    private CustomPopupWindow mCustomPopupWindow;

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

        mScrollView =findViewById(R.id.nested_scroll_view);

        mCustomPopupWindow = new CustomPopupWindow(this, mScrollView);
        mCustomPopupWindow.show();
    }
}

好了,本篇文章已經全部寫完了,有什麼疑問的,請在下面留言,存在不對的地方還望指導,感謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章