Weixin Official Accounts Platform

前外交部副部长傅莹:一旦中美闹翻,有没有国家会站在中国一边

终于找到了高清版《人间中毒》,各种姿势的图,都能看

去泰国看了一场“成人秀”,画面尴尬到让人窒息.....

2017年受难周每日默想经文(值得收藏!)

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

android ViewPager 仿画廊/图书翻页 与 palette 使用

徐公 2022-04-23


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

img

总结实现效果:

  • ViewPager 实现无限自动播放

  • ViewPager 实现中间大,两边小 [仿画廊效果]

  • ViewPager 实现图片叠加[仿图书翻页效果]

  • palette 调色板实现识别图片颜色,随着图片的变化来改变背景色的变化

普通ViewPager实现

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

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

activity_palette.xml布局:

在这里插入图片描述
java代码:


 1//设置适配器
2viewPager.setAdapter(new BannerAdapter(this, mDrawables));
3
4//Pager之间的间距
5viewPager.setPageMargin(20);
6
7//预加载
8viewPager.setOffscreenPageLimit(3);
9
10//默认第一张图 左右都有图
11viewPager.setCurrentItem(1);
12复制代码

BannerAdapter 适配器:

 1public class BannerAdapter extends PagerAdapter {
2    private int[] mData;
3    private Context mContext;
4
5    public BannerAdapter(Context ctx, int[] data) {
6        this.mContext = ctx;
7        this.mData = data;
8    }
9
10    @Override
11    public int getCount() {
12        return mData.length;// 返回数据的个数
13    }
14
15    @Override
16    public Object instantiateItem(final ViewGroup container, final int position) {//子View显示
17        View view = View.inflate(container.getContext(), R.layout.banner_item_layout, null);
18        ImageView imageView = view.findViewById(R.id.iv_icon);
19        imageView.setImageResource(mData[position]);
20
21        imageView.setOnClickListener(new View.OnClickListener() {
22            @Override
23            public void onClick(View view) {
24                Toast.makeText(mContext, "当前条目:" + position, Toast.LENGTH_SHORT).show();
25            }
26        });
27
28        container.addView(view);//添加到父控件
29        return view;
30    }
31
32    @Override
33    public boolean isViewFromObject(View view, Object object) {
34        return view == object;// 过滤和缓存的作用
35    }
36
37    @Override
38    public void destroyItem(ViewGroup container, int position, Object object) {
39        container.removeView((View) object);//从viewpager中移除掉
40    }
41}
42复制代码

先来看看目前的效果:

img

思路分析:

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

  • 让ViewPager显示出左右两侧的View

  • 无限滑动

  • 自定义ViewPager 滑动动画,滑动过程中中间大,两边小

  • 自动播放

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

让ViewPager显示出左右两侧的View

在这里插入图片描述
来看看效果:


img
在这里插入图片描述

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

来看看效果:

img

ViewPager.PageTransformer

先来看使用:

1viewPager.setPageTransformer(truenew ScaleTransformer());
2复制代码
  • 参数一: 是否逆转,我没看出有什么效果,懂这个参数的记得在评论区留言哦!

  • 参数二: 用来控制ViewPager 动画的

 1public class ScaleTransformer implements ViewPager.PageTransformer {
2    private static final float MAX_SCALE = 1.0f;//0缩放
3    private static final float MIN_SCALE = 0.80f;//0.85缩放
4
5
6    @Override
7    public void transformPage(@NonNull View view, float position) {
8
9    }
10}
11复制代码

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

 1   /**
2     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
3     * This offers an opportunity for the application to apply a custom transformation
4     * to the page views using animation properties.
5     *
6     * <p>As property animation is only supported as of Android 3.0 and forward,
7     * setting a PageTransformer on a ViewPager on earlier platform versions will
8     * be ignored.</p>
9     */

10    public interface PageTransformer {
11        /**
12         * Apply a property transformation to the given page.
13         *
14         * @param page Apply the transformation to this page
15         * @param position Position of page relative to the current front-and-center
16         *                 position of the pager. 0 is front and center. 1 is one full
17         *                 page position to the right, and -1 is one page position to the left.
18         */

19        void transformPage(@NonNull View page, float position);
20    }
21复制代码

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

 1@CallSuper
2    protected void onPageScrolled(int position, float offset, int offsetPixels) {
3
4        ....省略.......
5
6        if (mPageTransformer != null) {
7        ....省略.......
8
9                mPageTransformer.transformPage(child, transformPos);
10            }
11        }
12
13        mCalledSuper = true;
14    }
15复制代码

transformPage参数:

  • 参数一: 当前view

  • 参数二:当前view的位置

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

image.png
  • 红色当前View

  • 蓝色 左侧View

  • 黄色 右侧View

不滑动状态position变化:

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

滑动状态position变化:

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

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

在这里插入图片描述
还看不懂? 再来画一张图:


在这里插入图片描述

好了,position就介绍到这里!

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

 1public class ScaleTransformer implements ViewPager.PageTransformer {
2    private static final float MAX_SCALE = 1.0f;//0缩放
3    private static final float MIN_SCALE = 0.80f;//0.85缩放
4
5
6    @Override
7    public void transformPage(@NonNull View view, float position) {
8          //position != 0 表示左侧和右侧的view
9        if (position != 0) {
10            view.setScaleX(MIN_SCALE);
11            view.setScaleY(MIN_SCALE);
12        } else {
13            view.setScaleX(MAX_SCALE);
14            view.setScaleY(MAX_SCALE);
15        }
16    }
17}
18复制代码

效果:

img

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

 1public class ScaleTransformer implements ViewPager.PageTransformer {
2    private static final float MAX_SCALE = 1.0f;//0缩放
3    private static final float MIN_SCALE = 0.80f;//0.85缩放
4    @Override
5    public void transformPage(@NonNull View view, float position) {
6
7        if (position < 1) {
8            float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
9
10            view.setScaleX(scaleFactor);
11
12            view.setScaleY(scaleFactor);
13        } else {
14            view.setScaleX(MIN_SCALE);
15            view.setScaleY(MIN_SCALE);
16        }
17    }
18}
19复制代码

这里涉及到一个小算法

1 float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
2复制代码

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

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

来看看湿滑的效果:

img

无限自己滚动

这段代码也是简单的很:

直接上代码不多贝贝:

 1//用来记录是否按压,如果按压,则不滚动
2boolean isDown ;
3
4Timer timer = new Timer();
5
6   //定时器播放ViewPager
7        TimerTask timerTask = new TimerTask() {
8            @Override
9            public void run() {
10                if (!isDown) {
11                    //获取到当前的位置
12                    int page = viewPager.getCurrentItem() + 1;
13                    runOnUiThread(() -> viewPager.setCurrentItem(page));
14                }
15            }
16        };
17        // 每2.5秒执行一次
18       timer.schedule(timerTask, 02500);
19
20
21 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
22            @Override
23            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
24              //viewPager滑动的时候,设置不让滚动
25                isDown = true;
26            }
27
28            @Override
29            public void onPageSelected(int position) {
30
31            }
32
33            @Override
34            public void onPageScrollStateChanged(int state) {
35            //ViewPager不点击了让滚动
36                isDown = false;
37            }
38        });
39复制代码

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

仿图书效果

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

 1public class StackPageTransformer implements ViewPager.PageTransformer {
2    private final ViewPager viewPager;
3
4    private final float SCALE_VALUE = 1f;
5
6    //View 之间的偏移量
7    private final float DEVIATION = 60f;
8
9    //旋转
10    private final float ROTATION = 60f;
11
12    //图片是否叠加【默认不叠加】
13    private final boolean isStack = false;
14
15
16    public StackPageTransformer(ViewPager viewPager) {
17        this.viewPager = viewPager;
18    }
19
20    @Override
21    public void transformPage(@NonNull View view, float position) {
22        Log.i("szjPosition2", position + "");
23
24        /*
25         * 当不滑动状态下:
26         *      position = -1 左侧View
27         *      position = 0 当前View
28         *      position = 1 右侧View
29         *
30         * 当滑动状态下:
31         *  向左滑动: [ position < 0 && position > -1]
32         *    左侧View      position < -1
33         *    当前View    0 ~ -1
34         *    右侧View   1 ~ 0
35         *
36         * 向右滑动:[position > 0 && position < 1 ]
37         *   左侧View  -1 < position < 0
38         *   当前View  0 ~ 1
39         *   右侧View  position > 1
40         */

41
42        int pageWidth = viewPager.getWidth();
43
44        //隐藏左侧侧的view
45        if (position == -1) {
46            view.setVisibility(View.GONE);
47        } else {
48            view.setVisibility(View.VISIBLE);
49        }
50
51        //当前View和右侧的View [让右侧View和当前View叠加起来]
52        if (position >= 0) {
53            float translationX;
54            //这里不要晕! 改变isStack来看看效果吧!!
55            if (isStack) {
56                translationX = DEVIATION - (pageWidth) * position;
57            } else {
58                translationX = (DEVIATION - pageWidth) * position;
59            }
60            Log.i("szjTranslationX", translationX + "");
61            view.setTranslationX(translationX);
62        }
63
64        //当前view
65        if (position == 0) {
66            view.setScaleX(SCALE_VALUE);
67            view.setScaleY(SCALE_VALUE);
68        } else {
69            //左侧已经隐藏了,所以这里值的是右侧View的偏移量
70            float scaleFactor = Math.min(SCALE_VALUE - position * 0.1f, SCALE_VALUE);
71            view.setScaleX(scaleFactor);
72            view.setScaleY(scaleFactor);
73        }
74
75        //向左滑动
76        if (position < 0 && position > -1) {
77            //旋转
78            view.setRotation(ROTATION * position);
79            view.setAlpha(1 - Math.abs(position));
80        } else {
81            //透明度 其他状态不设置透明度
82            view.setAlpha(1);
83        }
84
85        //向右滑动
86        if (position > 0 && position < 1) {
87            view.setRotation(0);
88        }
89    }
90}
91复制代码

看看效果:

img

palette 调色板

先添加依赖:

1implementation 'com.android.support:palette-v7:26.0.0-alpha1'
2复制代码

简单介绍:

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

使用:

 1public void initPalette(Bitmap bitmap) {
2        new Thread(() -> Palette.from(bitmap).generate(palette -> {
3            //以RGB压缩整数的形式从调色板返回静音和深色。
4            int darkMutedColor = palette.getDarkMutedColor(Color.TRANSPARENT);
5
6            //暗 柔和 [以RGB压缩整数的形式从调色板返回静音和浅色。]
7            int lightMutedColor = palette.getLightMutedColor(Color.TRANSPARENT);
8
9            //暗 鲜艳 [以RGB压缩整数的形式从调色板返回深色和鲜艳的颜色。]
10            int darkVibrantColor = palette.getDarkVibrantColor(Color.TRANSPARENT);
11
12            //量 鲜艳 [以RGB压缩整数的形式从调色板返回明亮的颜色。]
13            int lightVibrantColor = palette.getLightVibrantColor(Color.TRANSPARENT);
14
15            //柔和 [将调色板中的静音颜色作为RGB压缩整数返回。]
16            int mutedColor = palette.getMutedColor(Color.TRANSPARENT);
17
18            //以RGB压缩整数形式返回调色板中最鲜艳的颜色。
19            int vibrantColor = palette.getVibrantColor(Color.TRANSPARENT);
20
21
22            //从调色板中返回一个明亮且充满活力的样例。可能为空。
23            Palette.Swatch lightVibrantSwatch = palette.getLightVibrantSwatch();
24
25            int hotColor = Color.TRANSPARENT;
26            if (lightVibrantSwatch != null) {
27                //谷歌推荐的:图片的整体的颜色rgb的混合痔---主色调
28                int rgb = lightVibrantSwatch.getRgb();
29                hotColor = getTranslucentColor(0.7f, rgb);
30            }
31
32        // 拿到颜色 这里就可以给View 设置颜色了 
33
34        })).start();
35    }
36复制代码

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

来看看效果:

img
 1 /**
2     * TODO 设置渐变颜色
3     *
4     * @param view   需要设置的View
5     * @param colors 渐变颜色
6     * @param type   渐变位置  例如:GradientDrawable.Orientation.LEFT_RIGHT 从左到右
7     * @param radius 圆角
8     */

9    public void setGradualChange(View view, int[] colors, GradientDrawable.Orientation type, int radius) {
10        GradientDrawable drawable = new GradientDrawable(type, colors);
11        drawable.setCornerRadius(radius);
12        view.setBackground(drawable);
13    }
14复制代码

完整项目:https://gitee.com/lanyangyangzzz/android_ui

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

推荐阅读

RecyclerView 多样式 Item  优雅解决方案

耗时一周,我解决了微信 Matrix 增量编译的 Bug,已提 PR

Android QMUI实战:实现APP换肤功能,并自动适配手机深色模式

Hook AMS + APT实现集中式登录框架

有点酷,仿京东首页体验的嵌套滑动吸顶效果

如果觉得对你有所帮助的话,可以关注我的微信公众号徐公,5 年中大厂工作经验。
  1. 公众号徐公回复黑马,获取 Android 学习视频
  2. 公众号徐公回复徐公666,获取简历模板,教你如何优化简历,走近大厂
  3. 公众号徐公回复面试,可以获得面试常见算法,剑指 ofer 题解
  4. 公众号徐公回复马士兵,可以获得马士兵学习视频一份






文章有问题?点此查看未经处理的缓存