android ViewPager 进阶(仿画廊/图书翻页) 与 palette 使用 (含完整Demo)

Posted android超级兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android ViewPager 进阶(仿画廊/图书翻页) 与 palette 使用 (含完整Demo)相关的知识,希望对你有一定的参考价值。

废话不多说,先来看看完成的效果!

总结实现效果:

  • ViewPager 实现无限自动播放
  • ViewPager 实现中间大,两边小 [仿画廊效果]
  • ViewPager 实现图片叠加[仿图书翻页效果]
  • palette 调色板实现识别图片颜色,随着图片的变化来改变背景色的变化

普通ViewPager实现

先不管三七二十一,先吧最基本的ViewPager实现,之后在在基本的ViewPager上修改!

不用复制代码,先看思路就行,底部会给出完整代码!

activity_palette.xml布局:

java代码:

//设置适配器
viewPager.setAdapter(new BannerAdapter(this, mDrawables));

//Pager之间的间距
viewPager.setPageMargin(20);

//预加载
viewPager.setOffscreenPageLimit(3);

//默认第一张图 左右都有图
viewPager.setCurrentItem(1);

BannerAdapter 适配器:

public class BannerAdapter extends PagerAdapter {
    private int[] mData;
    private Context mContext;

    public BannerAdapter(Context ctx, int[] data) {
        this.mContext = ctx;
        this.mData = data;
    }

    @Override
    public int getCount() {
        return mData.length;// 返回数据的个数
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {//子View显示
        View view = View.inflate(container.getContext(), R.layout.banner_item_layout, null);
        ImageView imageView = view.findViewById(R.id.iv_icon);
        imageView.setImageResource(mData[position]);

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(mContext, "当前条目:" + position, Toast.LENGTH_SHORT).show();
            }
        });

        container.addView(view);//添加到父控件
        return view;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;// 过滤和缓存的作用
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);//从viewpager中移除掉
    }
}

先来看看目前的效果:


就是一个很简单的ViewPager没什么好说的!

思路分析:

要想完成画廊的效果,那么必须吧viewPager分为以下几步骤:

  • 让ViewPager显示出左右两侧的View
  • 无限滑动
  • 自定义ViewPager 滑动动画,滑动过程中中间大,两边小
  • 自动播放

那就来根据思路实现效果吧 :

让ViewPager显示出左右两侧的View


来看看效果:


无限滑动

这个也是真 的简单,直接取%即可实现

来看看效果:


中间大,两边小效果
要想实现这个效果,就要来介绍本篇重中之重! ViewPager.PageTransformer

ViewPager.PageTransformer

先来看使用:

viewPager.setPageTransformer(true, new ScaleTransformer());
  • 参数一: 是否逆转,我没看出有什么效果,懂这个参数的记得在评论区留言哦!
  • 参数二: 用来控制ViewPager 动画的
public class ScaleTransformer implements ViewPager.PageTransformer {
    private static final float MAX_SCALE = 1.0f;//0缩放
    private static final float MIN_SCALE = 0.80f;//0.85缩放


    @Override
    public void transformPage(@NonNull View view, float position) {
        
    }
}

实现implements ViewPager.PageTransformer重写transformPage()方法,有2个参数

   /**
     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
     * This offers an opportunity for the application to apply a custom transformation
     * to the page views using animation properties.
     *
     * <p>As property animation is only supported as of Android 3.0 and forward,
     * setting a PageTransformer on a ViewPager on earlier platform versions will
     * be ignored.</p>
     */
    public interface PageTransformer {
        /**
         * Apply a property transformation to the given page.
         *
         * @param page Apply the transformation to this page
         * @param position Position of page relative to the current front-and-center
         *                 position of the pager. 0 is front and center. 1 is one full
         *                 page position to the right, and -1 is one page position to the left.
         */
        void transformPage(@NonNull View page, float position);
    }

这个方法在onPageScrolled页面滑动的过程中回调

@CallSuper
    protected void onPageScrolled(int position, float offset, int offsetPixels) {
        
        ....省略.......

        if (mPageTransformer != null) {
        ....省略.......
        
                mPageTransformer.transformPage(child, transformPos);
            }
        }

        mCalledSuper = true;
    }

transformPage参数:

  • 参数一: 当前view
  • 参数二:当前view的位置

这里比较抽象,画张图看看

  • 红色当前View
  • 蓝色 左侧View
  • 黄色 右侧View

不滑动状态position变化:

红色蓝色黄色
position = -1position = 0position = 1

滑动状态position变化:

状态红色蓝色黄色
左滑动position < -10 < position < -11 < position < 0
右滑动-1 < position < 00 < position < 1position > 1

先来打印一下看看position的值:

还看不懂? 再来画一张图:

好了,position就介绍到这里!

先简简单单修改代码,先看看效果:

public class ScaleTransformer implements ViewPager.PageTransformer {
    private static final float MAX_SCALE = 1.0f;//0缩放
    private static final float MIN_SCALE = 0.80f;//0.85缩放


    @Override
    public void transformPage(@NonNull View view, float position) {
      	//position != 0 表示左侧和右侧的view
        if (position != 0) {
            view.setScaleX(MIN_SCALE);
            view.setScaleY(MIN_SCALE);
        } else {
            view.setScaleX(MAX_SCALE);
            view.setScaleY(MAX_SCALE);
        }
    }
}

效果:


可以看到,要实现的效果已经渐渐接近了!

在加上滑动时候放大缩小即可

public class ScaleTransformer implements ViewPager.PageTransformer {
    private static final float MAX_SCALE = 1.0f;//0缩放
    private static final float MIN_SCALE = 0.80f;//0.85缩放
    @Override
    public void transformPage(@NonNull View view, float position) {
      
        if (position < 1) {
            float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
	
            view.setScaleX(scaleFactor);

            view.setScaleY(scaleFactor);
        } else {
            view.setScaleX(MIN_SCALE);
            view.setScaleY(MIN_SCALE);
        }
    }
}

这里涉及到一个小算法

 float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);

指的就是变化过程中view的大小

这段代码要细细的品味一下!!!很关键!!

来看看湿滑的效果:

无限自己滚动

这段代码也是简单的很:

直接上代码不多贝贝:

//用来记录是否按压,如果按压,则不滚动
boolean isDown ;

Timer timer = new Timer();

   //定时器播放ViewPager
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if (!isDown) {
                    //获取到当前的位置
                    int page = viewPager.getCurrentItem() + 1;
                    runOnUiThread(() -> viewPager.setCurrentItem(page));
                }
            }
        };
		// 每2.5秒执行一次
       timer.schedule(timerTask, 0, 2500);


 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
              //viewPager滑动的时候,设置不让滚动
                isDown = true;
            }

            @Override
            public void onPageSelected(int position) {
               
            }

            @Override
            public void onPageScrollStateChanged(int state) {
            //ViewPager不点击了让滚动
                isDown = false;
            }
        });

这段代码过于简单,就不看效果了!

仿图书效果

这个效果和仿画廊流程一样,也是对PageTransformer的操作,直接上代码了!

public class StackPageTransformer implements ViewPager.PageTransformer {
    private final ViewPager viewPager;

    private final float SCALE_VALUE = 1f;

    //View 之间的偏移量
    private final float DEVIATION = 60f;

    //旋转
    private final float ROTATION = 60f;

    //图片是否叠加【默认不叠加】
    private final boolean isStack = false;


    public StackPageTransformer(ViewPager viewPager) {
        this.viewPager = viewPager;
    }

    @Override
    public void transformPage(@NonNull View view, float position) {
        Log.i("szjPosition2", position + "");

        /*
         * 当不滑动状态下:
         *      position = -1 左侧View
         *      position = 0 当前View
         *      position = 1 右侧View
         *
         * 当滑动状态下:
         *  向左滑动: [ position < 0 && position > -1]
         *    左侧View      position < -1
         *    当前View    0 ~ -1
         *    右侧View   1 ~ 0
         *
         * 向右滑动:[position > 0 && position < 1 ]
         *   左侧View  -1 < position < 0
         *   当前View  0 ~ 1
         *   右侧View  position > 1
         */

        int pageWidth = viewPager.getWidth();

        //隐藏左侧侧的view
        if (position == -1) {
            view.setVisibility(View.GONE);
        } else {
            view.setVisibility(View.VISIBLE);
        }

        //当前View和右侧的View [让右侧View和当前View叠加起来]
        if (position >= 0) {
            float translationX;
            //这里不要晕! 改变isStack来看看效果吧!!
            if (isStack) {
                translationX = DEVIATION - (pageWidth) * position;
            } else {
                translationX = (DEVIATION - pageWidth) * position;
            }
            Log.i("szjTranslationX", translationX + "");
            view.setTranslationX(translationX);
        }

        //当前view
        if (position == 0) {
            view.setScaleX(SCALE_VALUE);
            view.setScaleY(SCALE_VALUE);
        } else {
            //左侧已经隐藏了,所以这里值的是右侧View的偏移量
            float scaleFactor = Math.min(SCALE_VALUE - position * 0.1f, SCALE_VALUE);
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
        }

        //向左滑动
        if (position < 0 && position > -1) {
            //旋转
            view.setRotation(ROTATION * position);
            view.setAlpha(1 - Math.abs(position));
        } else {
            //透明度 其他状态不设置透明度
            view.setAlpha(1);
        }

        //向右滑动
        if (position > 0 && position < 1) {
            view.setRotation(0);
        }
    }
}

看看效果:

palette 调色板

先添加依赖:

implementation 'com.android.support:palette-v7:26.0.0-alpha1'

简单介绍:
palette 传入一张Bitmap,然后他会通过图片像素点来分析出颜色占比,提取出你需要的颜色!!

使用:

public void initPalette(Bitmap bitmap) {
        new Thread(() -> Palette.from(bitmap).generate(palette -> {
            //以RGB压缩整数的形式从调色板返回静音和深色。
            int darkMutedColor = palette.getDarkMutedColor(Color.TRANSPARENT);

            //暗 柔和 [以RGB压缩整数的形式从调色板返回静音和浅色。]
            int lightMutedColor = palette.getLightMutedColor(Color.TRANSPARENT);

            //暗 鲜艳 [以RGB压缩整数的形式从调色板返回深色和鲜艳的颜色。]
            int darkVibrantColor = palette.getDarkVibrantColor(Color.TRANSPARENT);

            //量 鲜艳 [以RGB压缩整数的形式从调色板返回明亮的颜色。]
            int lightVibrantColor = palette.getLightVibrantColor(Color.TRANSPARENT);

            //柔和 [将调色板中的静音颜色作为RGB压缩整数返回。]
            int mutedColor = palette.getMutedColor(Color.TRANSPARENT);

            //以RGB压缩整数形式返回调色板中最鲜艳的颜色。
            int vibrantColor = palette.getVibrantColor(Color.TRANSPARENT);


            //从调色板中返回一个明亮且充满活力的样例。可能为空。
            Palette.Swatch lightVibrantSwatch = palette.getLightVibrantSwatch();

            int hotColor = Color.TRANSPARENT;
            if (lightVibrantSwatch != null) {
                //谷歌推荐的:图片的整体的颜色rgb的混合痔---主色调
                int rgb = lightVibrantSwatch.getRgb();
                hotColor = getTranslucentColor(0.7f, rgb);
            }
	
		// 拿到颜色 这里就可以给View 设置颜色了 

        })).start();
    }

然后通过随机图片,设置不同的图片来测试一下管用不管用!

来看看效果:


这里用到了动态代码设置渐变,代码很简单,给大家看看吧

 /**
     * TODO 设置渐变颜色
     *
     * @param view   需要设置的View
     * @param colors 渐变颜色
     * @param type   渐变位置  例如:GradientDrawable.Orientation.LEFT_RIGHT 从左到右
     * @param radius 圆角
     */
    public void setGradualChange(View view, int[] colors, GradientDrawable.Orientation type, int radius) {
        GradientDrawable drawable = new GradientDrawable(type, colors);
        drawable.setCornerRadius(radius);
        view.setBackground(drawable);
    }

完整项目

原创不易,您的点赞就是对我最大的支持!!

以上是关于android ViewPager 进阶(仿画廊/图书翻页) 与 palette 使用 (含完整Demo)的主要内容,如果未能解决你的问题,请参考以下文章

android 卡片画廊效果及RecycleView、ViewPager、ScrollView之前的冲突解决

Android -- 使用ViewPager实现画廊效果

android画廊怎样做出超炫效果

android画廊怎样做出超炫效果

Android中仿淘宝商品详情ViewPager页面数据手动滑动

ViewPager 仿 Gallery效果