Android利用PageView打造垂直的畫廊效果

首先放一下效果圖
在這裏插入圖片描述
這裏是採用FragmentPageView所打造的效果

打造這樣效果第一步就是先讓ViewPager垂直滑動
這裏使ViewPager垂直滑動的代碼參考這位大神的帖子
https://www.jianshu.com/p/d3065bbc1167
其核心思想就是攔截觸摸事件並反轉橫向和垂直滑動。

打造好垂直滑動效果之後剩下就變得簡單,首先想達到這樣一個效果需要將ViewPager及其父元素添加屬性android:clipChildren=“false”,使得其可以超出自身回追範圍
這裏上一下這個效果的佈局
在這裏插入圖片描述
因爲PageViewr和外面的ViewGroup大小相同,因此一開始看到的就是一個Fragment
之後爲PageViewr設置

//預加載Fragment數量
verticalPageView.setOffscreenPageLimit(3);
//兩個Fragment之間的間距
verticalPageView.setPageMargin(60);

如果再加上放大縮小就可以達到畫廊效果了…但是我這裏不需要,有需要的可以自己添加

之後再爲自定義的ViewPager重寫onInterceptTouchEvent,在裏面加上這樣一段代碼:

switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                this.animate().scaleX((float) 0.8).scaleY((float) 0.8).setDuration(300).start();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                this.animate().scaleX((float) 1.0).scaleY((float) 1.0).setDuration(300).start();
                break;
        }

注意這裏有一個坑,就是隻能觸發ACTION_DOWN事件,因此上面這些代碼應該在onInterceptTouchEvent一開始就調用

寫到現在應該就可以達到上面的效果了,但還有一個非常嚴重的問題,就是Fragment上面的點擊事件,這裏以上面的中止按鈕舉例

由於Android的觸摸事件是由頂層向下傳遞的,看上去沒什麼問題,但是這裏最頂層是ViewPager,因此無論如何都會先觸發ViewPager裏面的onInterceptTouchEvent,並執行縮放動畫。就算爲其中的按鈕執行onInterceptTouchEvent也只會讓ViewPager縮小並無法恢復,因爲只有ACTION_UP被阻攔

那麼就沒有辦法了麼?NO,這裏在ViewGroup之上的還有一個Activity,只要獲取按鈕在屏幕中的位置並根據觸摸點的位置判斷是否點擊到了按鈕即可。

這裏創建一個自定義接口

public interface IndexInterfaceForFragment {
    void sendWidget(View view);
}

Activity實現這個接口

@Override
    public void sendWidget(View view) {
        interceptViewArray.add(view);
    }

這裏我將控件都存入了一個數組中
之後Fragment在onCreateView中執行以下代碼

@Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_index_hint, container, false);

        //注意:這個functionButton發送到了Activity
        functionButton =view.findViewById(R.id.function_button);
        Random random = new Random();
        final int num = random.nextInt(100);
        functionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(),"functionbutton點擊了!"+num,Toast.LENGTH_SHORT).show();
            }
        });
        IndexInterfaceForFragment indexInterfaceForFragment =  (IndexInterfaceForFragment)getActivity();
        indexInterfaceForFragment.sendWidget(functionButton);
        return view;
    }

這裏可以看到,functionButton就是我們想阻攔的控件,通過

IndexInterfaceForFragment indexInterfaceForFragment = (IndexInterfaceForFragment)getActivity();
indexInterfaceForFragment.sendWidget(functionButton);

這種方式將控件發送到Activity中
在Activity中編寫以下代碼

public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN){
            if (!interceptEventControl(interceptViewArray,ev)){
                return false;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean interceptEventControl(ArrayList<View> arrayList, MotionEvent event){
        for (View v : arrayList){
            int[] location = {0,0};
            v.getLocationInWindow(location);
            Log.d("座標Button","X:"+location[0]+"Y:"+location[1]);
            int left = location[0],top = location[1],bottom = top + v.getHeight(),right = left+v.getWidth();
            if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom){
                //點擊到了要阻攔的控件
                v.callOnClick();
                return false;
            }
        }
        return true;
    }

這裏重寫了dispatchTouchEvent並調用interceptEventControl做判斷,在interceptEventControl中編寫了判斷點擊區域的邏輯,如果發現點擊了控件就阻攔點擊事件的傳遞並調用控件的callOnClick()方法以觸發其點擊事件。

嗯,到這裏就完成了最開始Gif的效果

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