ViewPager实现横滑居中缩放功能

需求描述

1.单行横滑海报列表,当前海报居中放大展示。
2.点击左边海报,左边海报居中变大,点击右边海报,右边海报居中变大。
3.点击居中放大海报实现跳转。
4.海报下方标题副标题实现联动效果。

实现效果

横滑缩放ViewPager.gif

实现思路

  • ViewPager自带居中属性,实现起来比RecylerView更方便(后续会针对RecylerView实现再写一篇),通过onPageScrolled监听中的positionOffset来实现
   /**
     * Callback interface for responding to changing state of the selected page.
     */
    public interface OnPageChangeListener {

        /**
         * This method will be invoked when the current page is scrolled, either as part
         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
         *
         * @param position Position index of the first page currently being displayed.
         *                 Page position+1 will be visible if positionOffset is nonzero.
         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
         * @param positionOffsetPixels Value in pixels indicating the offset from position.
         */
        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

        /**
         * This method will be invoked when a new page becomes selected. Animation is not
         * necessarily complete.
         *
         * @param position Position index of the new selected page.
         */
        void onPageSelected(int position);

        /**
         * Called when the scroll state changes. Useful for discovering when the user
         * begins dragging, when the pager is automatically settling to the current page,
         * or when it is fully stopped/idle.
         *
         * @param state The new scroll state.
         * @see ViewPager#SCROLL_STATE_IDLE
         * @see ViewPager#SCROLL_STATE_DRAGGING
         * @see ViewPager#SCROLL_STATE_SETTLING
         */
        void onPageScrollStateChanged(int state);
    }

positionOffset是当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0。positionOffsetPixels是当前页面滑动像素,变化情况和positionOffset一致。

  • 核心思路就是改变左右两端view的scale值。
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // 虽然一屏只显示三页,但是当我们滑动的过程中需要设置四页的缩放效果,因为左边的页面被滑出去之后,页面上将显示的是后面的三页
                View leftImage = mClipAdapter.activityMap.get(position - 1);
                View currentImage = mClipAdapter.activityMap.get(position);
                View rightImage = mClipAdapter.activityMap.get(position + 1);
                View rightImage2 = mClipAdapter.activityMap.get(position + 2);
                
                if (positionOffset >= 0) {

                    float scaleAlpha1 = 1 - positionOffset / 5.0f;
                    float scaleAlpha2 = mScale + positionOffset / 5.0f;

                    // 设置页面滑动过程中的缩放效果
                    currentImage.setAlpha(scaleAlpha1);
                    currentImage.setScaleX(scaleAlpha1);
                    currentImage.setScaleY(scaleAlpha1);
                    isViewInCenter(currentImage);
                    if (leftImage != null) {
                        leftImage.setAlpha(scaleAlpha2);
                        leftImage.setScaleX(scaleAlpha2);
                        leftImage.setScaleY(scaleAlpha2);
                        isViewInCenter(leftImage);
                    }
                    if (rightImage != null) {
                        rightImage.setAlpha(scaleAlpha2);
                        rightImage.setScaleX(scaleAlpha2);
                        rightImage.setScaleY(scaleAlpha2);
                        isViewInCenter(rightImage);
                    }
                    if (rightImage2 != null) {
                        rightImage2.setAlpha(scaleAlpha1);
                        rightImage2.setScaleX(scaleAlpha1);
                        rightImage2.setScaleY(scaleAlpha1);
                        isViewInCenter(rightImage2);
                    }
                } else {
                    // 设置页面初次启动时的缩放效果
                    if (leftImage != null && currentImage.getAlpha() == 1) {
                        leftImage.setAlpha(mScale);
                        leftImage.setScaleX(mScale);
                        leftImage.setScaleY(mScale);
                    }
                    if (rightImage != null && currentImage.getAlpha() == 1) {
                        rightImage.setAlpha(mScale);
                        rightImage.setScaleX(mScale);
                        rightImage.setScaleY(mScale);
                    }
                }
            }

            @Override
            public void onPageSelected(int position) {
                setTitle(position);
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });

float scaleAlpha1 = 1 - positionOffset / 5.0f;这里为什么是除以5.0f?是因为我们要求的scale值是0.8,明白了?哈哈

  • 左右海报点击效果解决方案,直接上代码
  public class SingleLineZoomViewPager extends ViewPager {

    private final int VIEW_MOVE_TAG = 1;
    //28:两边间隔10+10 中间间隔4+4
    private int width = (UIsUtils.getMinScreen() - UIsUtils.dipToPx(28)) / 3 ;
    private int height = width * 4 /3;
    private int zoomWidth = width *5/4;
    private int zommHeight = height * 5 /4 ;


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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_UP) {

            int[] location = new int[2];

            SingleLineZoomViewPager.this.getLocationOnScreen(location);


            int minX = location[0];
            int minY = location[1];
            //得到view的最右侧坐标
            int maxX = location[0] + zoomWidth;
            int maxY = location[1]+ zommHeight;
            //          手指触摸的坐标
            float x = ev.getRawX();
            float y = ev.getRawY();
            int item = getCurrentItem();
            if ((x > maxX) && (y > minY && y < maxY)) {
                LogInfo.log("abc","click right --->  + "+ item);
                ((ClipAdapter)getAdapter()).mCanClick = false;
                setCurrentItem(item + 1);
            } else if ((x < minX) && (y > minY && y < maxY)) {
                LogInfo.log("abc","click left ---> "+ item);
                ((ClipAdapter)getAdapter()).mCanClick = false;
                setCurrentItem(item -1);
            }else{
                ((ClipAdapter)getAdapter()).mCanClick = true;
            }
        }
        return super.dispatchTouchEvent(ev);
    }
}

float x = ev.getRawX();
float y = ev.getRawY();要用getRawX()和getRawY()注意~

  • 居中海报跳转
        
imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mCanClick){
                    imageView.getTag();
                    UIControllerUtils.gotoActivity(mContext, bean, PlayUtils.getVideoType(mCid, bean.isPanorama()), mPageId);
                }

            }
        });

通过mCanClick标记来确定
- 4.海报下方标题副标题实现联动效果。这里比较低效的使用一个isViewInCenter函数来判断,并实现联动

 
    public void isViewInCenter(View view){
        int[] location = new int[2];

        view.getLocationOnScreen(location);
        int x = location[0] + zoomWidth/2;
        if((x > (center - (zoomWidth/2)) && x < (center + (zoomWidth/2)) )){
            Log.e("abc", "view.getTag() "+ view.getTag());
            if(view.getTag() != null){
                setTitle((int)view.getTag());
            }
        }
    }

至此,所有需要解决问题均解决。

你可能感兴趣的:(ViewPager实现横滑居中缩放功能)