看到知乎中,文章下侧会跟着一个广告banner,上下滑动文章时会根据方向,进行扇形的切换。git
闲来无事就写个玩玩,本人菜鸡,初步想的就是两层ImageView重叠,对上层的IV进行裁剪操做,遂,直接开撸(demo功能演示,代码可能不漂亮还请见谅)。github
布局大体样式canvas
ScrollView
content view
framelayout/relativelayout都可
imageView id:iv_below
imageView id:iv_above
framelayout/relativelayout都可
content view
复制代码
咱们只须要对 iv_above 进行裁剪操做便可bash
首先得到iv_above的bitmap网络
bmAbove = ((BitmapDrawable)ivOrange.getDrawable()).getBitmap();
复制代码
对滚动进行监听:ide
(实际上知乎的功能是对滑动方向进行判断后,直接开始进行动画,扇形半径并不跟滑动距离有关联,当滑动方向与上次的相反时,中止上次的动画,再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;
}
复制代码
用到paint.setXfermode,传入new PorterDuffXfermode 能够对2d图像的合成模式进行设置。 (.setXfermode这个方法功能很复杂也很强大,有兴趣的能够去百度一下)动画
总计有18个合成模式:ui
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地址:
[github.com/bladeofgod/…](demo 地址)