1. 程式人生 > >解決ViewPager設定切換動畫PageTransformer後子頁無法觸控的問題

解決ViewPager設定切換動畫PageTransformer後子頁無法觸控的問題

通過ViewPager.setPageTransformer()方法可以設定切換動畫,但是如果ViewPager的子頁中要處理觸控事件,如瀏覽圖片時對圖片放大縮小,ViewPager切換子頁後,不能處理觸控事件,似乎子頁裡面的變的不可點選。嘗試了很多中Google上的方法,仍不能解決問題。其實這個是android4.1+版本上的bug,在呼叫了setPageTransformer()方法後,切換子頁後,當前最上面的View並不是眼睛所看的,而是另一個隱藏的子頁,該隱藏的子頁消費了觸控事件。嘗試了把當前子頁“放到最上面”,view.bringToFornt(),甚至把其他看不見的子頁都設定為隱藏,otherView.setVisibility(View.GONE),當前子頁仍然不能處理觸控事件。

最後查看了viewPager的原始碼,發現執行切換動畫的程式碼在onPageScrolled()方法內:

if(this.mPageTransformer != null) {
            scrollX = this.getScrollX();
            childCount = this.getChildCount();

            for(i = 0; i < childCount; ++i) {
                View var15 = this.getChildAt(i);
                ViewPager.LayoutParams var16 = (ViewPager.LayoutParams)var15.getLayoutParams();
                if(!var16.isDecor) {
                    float var17 = (float)(var15.getLeft() - scrollX) / (float)this.getClientWidth();
                    this.mPageTransformer.transformPage(var15, var17);
                }
            }
        }

其中的mPageTransformer就是setPageTransformer()傳進來的引數。於是,解決的方法便出來了:
public class SimpleViewPager extends ViewPager {

    private PageTransformer mPageTransformer;

    public SimpleViewPager(Context context) {
        this(context, null);
    }

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

    /**
     * android4.1+設定PageTransformer會使ViewPager的子頁裡面的觸控事件異常
     * (當前看到的子頁並非在最上面,所以觸控事件被隱藏在其上面的View給消費了)
     * 所以結合setPageTransformer(),在onPageScrolled()裡“手動”呼叫切換頁面的動畫
     *
     * @param position
     * @param offset
     * @param offsetPixels
     */
    @Override
    protected void onPageScrolled(int position, float offset, int offsetPixels) {
        super.onPageScrolled(position, offset, offsetPixels);
        // 下面的原始碼來自super.onPageScrolled()
        int scrollX;
        int childCount;
        int i;
        if (this.mPageTransformer != null) {
            scrollX = this.getScrollX();
            childCount = this.getChildCount();

            for (i = 0; i < childCount; ++i) {
                View var15 = this.getChildAt(i);
                ViewPager.LayoutParams var16 = (ViewPager.LayoutParams) var15.getLayoutParams();
                if (!var16.isDecor) {
                    float var17 = (float) (var15.getLeft() - scrollX) / (float) this.getClientWidth();
                    this.mPageTransformer.transformPage(var15, var17);
                }
            }
        }
    }

    private int getClientWidth() {
        return this.getMeasuredWidth() - this.getPaddingLeft() - this.getPaddingRight();
    }

    /**
     * 覆蓋該方法,不設定PageTransformer,以成員變數的形式儲存PageTransformer
     *
     * @param reverseDrawingOrder
     * @param transformer
     */
    @Override
    public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
        super.setPageTransformer(reverseDrawingOrder, null);
        mPageTransformer = transformer;
    }

}


原理很簡單,既然是因為設定了PageTransformer才導致子頁的觸控事件異常,那麼就不設定該屬性,通過間接的方式執行切換動畫。上面的類繼承了ViewPager,覆蓋了setPageTransformer()和onPageScrolled(),儲存傳進來的PageTransformer物件,父類ViewPager的mPageTransformer實際上為空,在onPageScrolled()方法中“手動執行”切換動畫。