【闲来无事】仿知乎广告Banner的切换功能

开头

看到知乎中,文章下侧会跟着一个广告banner,上下滑动文章时会根据方向,进行扇形的切换。

闲来无事就写个玩玩,本人菜鸡,初步想的就是两层ImageView重叠,对上层的IV进行裁剪操作,遂,直接开撸(demo功能演示,代码可能不漂亮还请见谅)。

布局

布局大致样式

ScrollView
    content view
        framelayout/relativelayout均可
                imageView id:iv_below
                imageView id:iv_above
        framelayout/relativelayout均可
    content view

实现

我们只需要对 iv_above 进行裁剪操作即可

首先获得iv_above的bitmap

bmAbove = ((BitmapDrawable)ivOrange.getDrawable()).getBitmap();
对滚动进行监听:

(实际上知乎的功能是对滑动方向进行判断后,直接开始进行动画,扇形半径并不跟滑动距离有关联,当滑动方向与上次的相反时,停止上次的动画,再reverse,这样做的好处就是在滑动时进行了最少的运算,避免了潜在的滑动卡顿,我还是直接关联扇形半径和滑动距离)

      private float screenWidth;
    private float threshold = 500;
        scrollView.setListener(new MyScrollView.onScrollListener() {
            @Override
            public void onScroll(int l, int t, int oldl, int oldt) {
                float curY = (float)t;
                if(t > oldt){
                    //scroll down
                    isScrollUp = false;
                    float r = curY / threshold ;
                    ivOrange.setImageBitmap(circleBitmap(bmOrange, r * screenWidth));
                }else{
                    isScrollUp = true;
                    float r = curY / threshold ;
                    ivOrange.setImageBitmap(circleBitmap(bmOrange, r * screenWidth));
                }
            }
        });
裁剪

    private Bitmap circleBitmap(Bitmap o,float radius){
        Bitmap outputBm = Bitmap.createBitmap(o.getWidth(),o.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(outputBm);
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);

        final Rect rect = new Rect(0,0,o.getWidth(),o.getHeight());
        canvas.drawARGB(0,0,0,0);
        canvas.drawCircle(0,0,radius,paint );
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(o,rect,rect,paint);
        return outputBm;
    }
裁剪
 private Bitmap circleBitmap(Bitmap o,float radius){
        Bitmap outputBm = Bitmap.createBitmap(o.getWidth(),o.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(outputBm);
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);

        final Rect rect = new Rect(0,0,o.getWidth(),o.getHeight());
        canvas.drawARGB(0,0,0,0);
        canvas.drawCircle(0,0,radius,paint );
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(o,rect,rect,paint);
        return outputBm;
    }

用到paint.setXfermode,传入new PorterDuffXfermode 可以对2d图像的合成模式进行设置。

(.setXfermode这个方法功能很复杂也很强大,有兴趣的可以去百度一下)

总计有18个合成模式:

CLEAR/
SRC/
DST/
SRC_OVER/
DST_OVER
SRC_IN/
DST_IN/
SRC_OUT/
DST_OUT/
SRC_ATOP/
DST_ATOP/
XOR/
DARKEN/
LIGHTEN/
MULTIPLY/
SCREEN/
ADD/
OVERLAY/

合成样式如下图(来源自网络):

这里是用的是SRC_IN 模式,通过绘制一个圆形(半径radius,并会增减),与原bmAbove重叠,之后取相交的部分作为bitmap返回,达到裁剪的效果。

结束

至此整个功能就实现了,当然代码还有很多可以优化的地方,以及其他实现方式,欢迎大家留言一起交流。

demo地址:

https://github.com/bladeofgod/ZhiHu_Banner_Switch

阿里P6P7【安卓】进阶资料分享+加薪跳槽必备面试题

发布了452 篇原创文章 · 获赞 78 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/Coo123_/article/details/104255812