Android仿转转首页banner

《Android仿转转首页banner》 banner_g–.gif

代码地址:Github

效果由来

我司设计一向比较喜欢高大上的东西(我也喜欢…),无意中看到转转首页banner动画不错,想得之,由于项目工期和人手限制,遭到IOS开发和我的强烈反对,设计也即将妥协,我抱着猎奇心态(手欠)搜了下网上看看有没有类似效果,结果让我搜到了iOS版本 ,iOS开发欢心集成,我则愁眉苦展,辗转两天之久,出此代码.

具体效果

  • 底部背景图片随着banner滚动实现reveal效果
  • banner上层图片缩放效果

实现原理

  • 上层banner用viewPager实现,通过handler定时发送消息实现可循环自动播放的banner
  • 下层背景图片通过多张图片折叠,然后通过viewPager滚动监听来操作底部图片的显示和隐藏
  • 缩放动画用属性动画实现,根据viewPager滑动停止和移动判断是否放大或缩小

特性

  • 可独立拆分使用,设置属性可变为普通banner,修改如需特殊要求可修改源码item_banner.xml布局即可

部分关键代码

    private class ViewPageChangeListener implements ViewPager.OnPageChangeListener {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            // 判断viewPager左右滑动相关
            if (mViewPagerIndex == position) {
                if (bannerBgContainer.getBannerBgViews().size() > position % bannerBgContainer.getBannerBgViews().size() + 1) {
                    bannerBgContainer.getBannerBgViews().get(position % bannerBgContainer.getBannerBgViews().size() + 1).bringToFront();
                    bannerBgContainer.getBannerBgViews().get(position % bannerBgContainer.getBannerBgViews().size() + 1)
                            .hideClipAnimation((positionOffset - reduceValue) * upValue > 1 ? 1 : (positionOffset - reduceValue) * upValue);
                } else if (bannerBgContainer.getBannerBgViews().size() == position % bannerBgContainer.getBannerBgViews().size() + 1) {
                    bannerBgContainer.getBannerBgViews().get(0).bringToFront();
                    bannerBgContainer.getBannerBgViews().get(0)
                            .hideClipAnimation((positionOffset - reduceValue) * upValue > 1 ? 1 : (positionOffset - reduceValue) * upValue);
                }
            } else {
                if (position / bannerBgContainer.getBannerBgViews().size() >= 0) {
                    bannerBgContainer.getBannerBgViews().get(position % bannerBgContainer.getBannerBgViews().size()).bringToFront();
                    bannerBgContainer.getBannerBgViews().get(position % bannerBgContainer.getBannerBgViews().size())
                            .showClipAnimation(0, bannerBgContainer.getHeight() / 2,
                                    (1 - (positionOffset + reduceValue)) * upValue > 1 ? 1 : (1 - (positionOffset + reduceValue)) * upValue);
                }
            }

        }

        @Override
        public void onPageSelected(int position) {
            int i = position % bannerInfos.size();
            if (i == 0) {
                animIndicator.setTranslationX(totalDistance * 0.0f);
            } else if (i == bannerInfos.size() - 1) {
                animIndicator.setTranslationX(totalDistance * 1.0f);
            }
            // 不是手动拖拽时, 当前position 减1 因为setCurrentItem方法会在滑动之前把position设置成当前位置(此处是坑)
            mViewPagerIndex = position - 1;
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            // 如果是手动拖拽,则取当前位置
            if (state == 1) {
                if (loopViewPager != null) {
                    mViewPagerIndex = loopViewPager.getCurrentItem();
                }
            }
        }
    }

使用方法

  • 在 app的build.gradle 里面引用
implementation 'com.tokiii:reveal-banner:1.0.0'
  • 布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="240dp">

    <com.wikikii.bannerlib.banner.view.BannerBgContainer
        android:id="@+id/banner_bg_container"
        android:layout_width="match_parent"
        android:layout_height="240dp" />


    <com.wikikii.bannerlib.banner.LoopLayout
        android:id="@+id/loop_layout"
        android:layout_width="match_parent"
        android:layout_height="168dp"
        android:layout_gravity="bottom" />
</FrameLayout>
  • 代码设置属性
        // 设置轮播图属性
        loopLayout.setLoop_ms(3000);//轮播的速度(毫秒)
        loopLayout.setLoop_duration(400);//滑动的速率(毫秒)
        loopLayout.setScaleAnimation(true);// 设置是否需要动画
        loopLayout.setLoop_style(LoopStyle.Empty);//轮播的样式-默认empty
        loopLayout.setIndicatorLocation(IndicatorLocation.Center);//指示器位置-中Center
        loopLayout.initializeData(this);
        // 设置轮播图属性end
        
        // 准备数据
        ArrayList<BannerInfo> bannerInfos = new ArrayList<>();
        List<Object> bgList = new ArrayList<>();
        bannerInfos.add(new BannerInfo(R.mipmap.banner_1, "first"));
        bannerInfos.add(new BannerInfo(R.mipmap.banner_2, "second"));
        bgList.add(R.mipmap.banner_bg1);
        bgList.add(R.mipmap.banner_bg2);
        // 设置监听
        loopLayout.setOnLoadImageViewListener(new OnDefaultImageViewLoader() {
            @Override
            public void onLoadImageView(ImageView view, Object object) {
                Glide.with(view.getContext())
                        .load(object)
                        .into(view);
            }
        });
        loopLayout.setOnBannerItemClickListener(this);
        if (bannerInfos.size() == 0) {
            return;
        }
        loopLayout.setLoopData(bannerInfos);// 设置轮播数据
        bannerBgContainer.setBannerBackBg(this, bgList);// 背景容器设置轮播图片
        loopLayout.setBannerBgContainer(bannerBgContainer);// 联动
        loopLayout.startLoop();// 开始循环

后记

详细请看具体代码已经上传到Github ,由于时间仓促,实际效果与转转还是多少有些不同,代码注释较少,等后续优化接近完美会补上关键代码逻辑和原理(也没有多复杂),敬请期待…..

    原文作者:tokiii
    原文地址: https://www.jianshu.com/p/2475a15ee5d2
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞