Wishing you peace, joy and happiness through the coming year.
提交祝贺大家新春快乐,狗年行大运。
在年前跟大家分享一款滑动视差控件,先看效果图:
由于录制的不是很清晰,请下载源码运行看效果。ScrollParallaxView 控件支持以下个性化定制,并支持链式的调用:
支持非图片区域的背景颜色设置
链式调用的方式如下:
((ScrollParallaxView) helper.getView(R.id.spv))
.setEnableCircle(false)
.setRoundWidth(16)
.setEmptyAreaColor(Color.parseColor("#FFFFFF"));
就用语言描述吧,原理图我画的实在太丑了,都不好意思放上来了。
一句话概括:先将图片放大,然后根据滑动的偏移量来对图片进行平移处理。
原理就是这么简单,这么任性,接下来看看具体的实现。
首先需要针对滑动事件的监听,为了降低耦合,直接注册监听视图树的滑动事件:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnScrollChangedListener(this);
}
既然有添加,那么就有移除:
@Override
protected void onDetachedFromWindow() {
getViewTreeObserver().removeOnScrollChangedListener(this);
super.onDetachedFromWindow();
}
ScrollParallaxView 视图在滚动的时候进行重绘:
@Override
public void onScrollChanged() {
//重绘
invalidate();
}
invalidate() 方法会调用 onDraw() 方法,接着看看 onDraw() 方法进行了哪些操作:
@Override
protected void onDraw(Canvas canvas) {
if (enableScrollParallax) {
int saveCount = canvas.save();
getLocationInWindow(mViewLocation);
mActualRect = getDrawable().getBounds();
//视图宽度
float vw = getWidth();
//视图高度
float vh = getHeight();
//图片宽度
float bw = mActualRect.width();
//图片高度
float bh = mActualRect.height();
//视图宽高比
float vratio = vw / vh;
//图片宽高比
float bratio = bw / bh;
//最大滑动高度
float ph = (1 + parallaxMultiplier) * vh;
if (bratio > vratio) {
parallaxScale = ph / (vw / bratio);
} else {
float _scale = vw / (vh * bratio);
float _ph = vw / bratio;
if (_ph < ph) {
_scale = ph / vh;
}
parallaxScale = _scale;
}
//重置矩阵
mParallaxMatrix.reset();
mParallaxMatrix.mapRect(new RectF(mActualRect));
//居中缩放
mParallaxMatrix.postScale(parallaxScale, parallaxScale, vw / 2, vh / 2);
//增加滑动偏移量,让滑动从图片顶部开始
float translationY = parallaxMultiplier / 2f * vh;
mParallaxMatrix.postTranslate(0, translationY);
//滚动偏移
int dHeight = getResources().getDisplayMetrics().heightPixels;
mParallaxMatrix.postTranslate(0, -(parallaxMultiplier * vh) * ((float) mViewLocation[1] / dHeight));
canvas.concat(mParallaxMatrix);
super.onDraw(canvas);
canvas.restoreToCount(saveCount);
} else {
super.onDraw(canvas);
}
canvas.drawPath(mRoundPath, mRoundPaint);
}
首先是获取到视图在屏幕当中的坐标:
getLocationInWindow(mViewLocation);
然后获取到图片的矩形区域:
mActualRect = getDrawable().getBounds();
接着是获取到图片的缩放比例:
//视图宽度
float vw = getWidth();
//视图高度
float vh = getHeight();
//图片宽度
float bw = mActualRect.width();
//图片高度
float bh = mActualRect.height();
//视图宽高比
float vratio = vw / vh;
//图片宽高比
float bratio = bw / bh;
//最大滑动高度
float ph = (1 + parallaxMultiplier) * vh;
//等比缩放,防止变形
if (bratio > vratio) {
parallaxScale = ph / (vw / bratio);
} else {
float _scale = vw / (vh * bratio);
float _ph = vw / bratio;
if (_ph < ph) {
_scale = ph / vh;
}
parallaxScale = _scale;
}
最后对图片进行缩放,平移的操作:
//重置矩阵
mParallaxMatrix.reset();
mParallaxMatrix.mapRect(new RectF(mActualRect));
//居中缩放
mParallaxMatrix.postScale(parallaxScale, parallaxScale, vw / 2, vh / 2);
//增加滑动偏移量,让滑动从图片顶部开始
float translationY = parallaxMultiplier / 2f * vh;
mParallaxMatrix.postTranslate(0, translationY);
//滚动偏移
int dHeight = getResources().getDisplayMetrics().heightPixels;
mParallaxMatrix.postTranslate(0, -(parallaxMultiplier * vh) * ((float) mViewLocation[1] / dHeight));
canvas.concat(mParallaxMatrix);
代码我并没有细讲,请原谅我的懒惰。如果有不懂的地方请留言,如果你有更好的方式也请留言讨论。
接下来,我跟大家分享一个跟本文无关的故事。
在面试过程中,怎么去实现以下的控件效果:
来源:MEIOS4.0 手机设置页面顶部效果。
以上效果图是我个人实现的效果,有一些细节需要调整,因为我没有参数。只能实现了一个类似的效果。
实现的过程当中遇到的第一个难题就是,怎么实现多边形的圆角问题?四边形系统直接提供了方法,那么三边形,五边形,多边形呢?如果我每个角去画,那么真的会很酸爽。
画笔 Paint 有个方法 setPathEffect 可以设置画笔的路径样式。PathEffect 有个子类 CornerPathEffect 把拐角绘制成圆角效果。接着你会发现,始终有一个角是直角,怎么也绘制不成圆角的效果,那么又怎么解决呢?欢迎留言给出你的方案,透密一下很简单哟。
本篇到此就差不多结束了,谢谢大家的关注。也希望能推送一些对大家有帮助的文章。