自定义 Custom Drawables
我们都看过关于为什么你应该适当的使 自定义 Views 和如何能帮助你正确的封装你的应用程序代码的帖子。但非视图相关的部分如何转化为我们 apps 的其他部分的这种思考方式,我们对此并不非常了解。
在我的应用 Fragment 中,有些地方我使用自定义 Drawables 来封装我的逻辑,就像你在 customView 中做的一样。
用例
在 Fragment 中,有一些使用水平滚动条作为一个选择视图的地方。这意味着该中心图标就是“选中”的图标,整个条目就该平滑的平移进去或平移出。为此,一个好的显示转换将非常棒。
虽然这并非完全必要,但我觉得它是一个能让这个滑动更加流畅并增加一个触摸的类在 app 上的效果。我本可以设置多个 imageviews 并让他们每个独立出来,但这真是使用自定义 drawables 的好地方~
自定义 Drawables
在 Android 里,Drawables 和 Views 实际上非常的相似。他们有相似的方法,例如 padding 和 bounds(layout),并且都有一个可以被重写的 draw 方法。就我而言,我需要能够在一个选中的图片和一个未选中的图片之间进行转换基础上的一个值。
在我们的例子中,我们简单地创建一个包含其他 Drawables(和方向) 的 Drawable 子类.
public class RevealDrawable extends Drawable {
public RevealDrawable(Drawable unselected, Drawable selected, int orientation) {
this(null, null);
mUnselectedDrawable = unselected;
mSelectedDrawable = selected;
mOrientation = orientation;
}
}
接下来,我们需要设定能够与图片选择过程中相关联的值。幸运的是 Drawable 内置了这种类型的事件,setLevel(int).
一个 Drawable 的 level 是介于 0 和 10000 的整数,它只是允许 Drawable 基于一个值去自定义它的 view.在我们的例子中,我们可以定义 5000 作为图片被选择时的状态值,其他没被选中状态值在 5000 左右两侧。 All we need to do now is to override the draw(Canvas canvas) method to draw the appropriate drawable by clipping the canvas based on the current level. 现在我们要做的就是重写 draw(Canvas canvas) 方法,通过基于当前的 level 裁剪画布去绘制相应的图片。
@Override
public void draw(Canvas canvas) {
// If level == 10000 || level == 0, just draw the unselected image
int level = getLevel();
if (level == 10000 || level == 0) {
mRevealState.mUnselectedDrawable.draw(canvas);
}
// If level == 5000 just draw the selected image
else if (level == 5000) {
mRevealState.mSelectedDrawable.draw(canvas);
}
// Else, draw the transitional version
else {
final Rect r = mTmpRect;
final Rect bounds = getBounds();
{ // Draw the unselected portion
float value = (level / 5000f) - 1f;
int w = bounds.width();
if ((mRevealState.mOrientation & HORIZONTAL) != 0) {
w = (int) (w * Math.abs(value));
}
int h = bounds.height();
if ((mRevealState.mOrientation & VERTICAL) != 0) {
h = (int) (h * Math.abs(value));
}
int gravity = value < 0 ? Gravity.LEFT : Gravity.RIGHT;
Gravity.apply(gravity, w, h, bounds, r);
if (w > 0 && h > 0) {
canvas.save();
canvas.clipRect(r);
mRevealState.mUnselectedDrawable.draw(canvas);
canvas.restore();
}
}
{ // Draw the selected portion
float value = (level / 5000f) - 1f;
int w = bounds.width();
if ((mRevealState.mOrientation & HORIZONTAL) != 0) {
w -= (int) (w * Math.abs(value));
}
int h = bounds.height();
if ((mRevealState.mOrientation & VERTICAL) != 0) {
h -= (int) (h * Math.abs(value));
}
int gravity = value < 0 ? Gravity.RIGHT : Gravity.LEFT;
Gravity.apply(gravity, w, h, bounds, r);
if (w > 0 && h > 0) {
canvas.save();
canvas.clipRect(r);
mRevealState.mSelectedDrawable.draw(canvas);
canvas.restore();
}
}
}
}
就这样,我们可基于滑动的位置以简单地设置 icon 的 level,结束了~
float offset = getOffestForPosition(recyclerView, position);
if (Math.abs(offset) <= 1f) {
holder.image.setImageLevel((int) (offset * 5000) + 5000);
} else {
holder.image.setImageLevel(0);
}
想要看自定义 Drawable 源码,请在 Github 上搜索 Gist here
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Android 进行单元测试难在哪?序
下一篇: 自动化截图-应用分发时的自动截图方案
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论