您的位置:首页 > 其它

深度剖析之 TextDrawable

2016-01-07 17:58 141 查看
剖析项目名称: TextDrawable

剖析原项目地址https://github.com/amulyakhare/TextDrawable

剖析理由:只知其然而不知其所以然,如此不好。想要快速的进阶,不走寻常路,剖析开源项目,深入理解扩展知识,仅仅这样还不够,还需要如此:左手爱哥的设计模式,右手重构改善既有设计,如此漫长打坐,回过头再看来时的路,书已成山,相信翔哥说的,量变引起质变

先看整体效果图:



这个轻量级的库提供了矩形、圆角、圆形的文本图供ImageView使用。Android Studio项目导入:

repositories{
maven {
url 'http://dl.bintray.com/amulyakhare/maven'
}
}

dependencies {
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
}


xml引用实例(指定ImageView宽度/高度和可拉的自动扩展以适应大小。):

<ImageView android:layout_width="60dp"
android:layout_height="60dp"
android:id="@+id/image_view"/>


代码调用实例和效果:



TextDrawable drawable = TextDrawable.builder()
.buildRect("A", Color.RED);

ImageView image = (ImageView) findViewById(R.id.image_view);
image.setImageDrawable(drawable);


以上实例才用的是默认图形,我们还可以选择圆角或圆形,可以设置边框,代码调用实例和效果图如下:





TextDrawable drawable1 = TextDrawable.builder()
.buildRoundRect("A", Color.RED, 10); // radius in px

TextDrawable drawable2 = TextDrawable.builder()
.buildRound("A", Color.RED);
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.withBorder(4) /* thickness in px */
.endConfig()
.buildRoundRect("A", Color.RED, 10);


修改字体样式代码调用实例:

TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.textColor(Color.BLACK)
.useFont(Typeface.DEFAULT)
.fontSize(30) /* size in px */
.bold()
.toUpperCase()
.endConfig()
.buildRect("a", Color.RED)


颜色辅助类调用实例:

ColorGenerator generator = ColorGenerator.MATERIAL; // or use DEFAULT
// generate random color
int color1 = generator.getRandomColor();
// generate color based on a key (same key returns the same color), useful for list/grid views
int color2 = generator.getColor("user@gmail.com")

// declare the builder object once.
TextDrawable.IBuilder builder = TextDrawable.builder()
.beginConfig()
.withBorder(4)
.endConfig()
.rect();

// reuse the builder specs to create multiple drawables
TextDrawable ic1 = builder.build("A", color1);
TextDrawable ic2 = builder.build("B", color2);


大概聊了整个项目后,发现需要我们有两个类:ColorGenerator 和 TextDrawable ,ColorGenerator 内部预定义了一些了的色值存放到集合,然后需要用时再从里面取出,这里就不细说了,重点放在TextDrawable

,该类运用builder模式,设置相关属性,构建TextDrawable,先来看下主体结构:

/**
* @author amulya
* @datetime 14 Oct 2014, 3:53 PM
*/
public class TextDrawable extends ShapeDrawable {

private TextDrawable(Builder builder) {
//调用父类构造含shape
super(builder.shape);

// 把Builder属性引用到ShapeDrawable
shape = builder.shape;
height = builder.height;
width = builder.width;
radius = builder.radius;
//...............此处略......................

// 初始化画笔
Paint paint = getPaint();
paint.setColor(color);

}

public static interface IBuilder {...}
public static interface IShapeBuilder {...}
public interface IConfigBuilder {...}
public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder {...}
}


TextDrawable的构造函数调用的父类的含shape构造方法,而这里的传入Builder类在初始化的时候就初始化了shape的子类RectShape:

private Builder() {
//初始化基本属性
text = "";
color = Color.GRAY;
shape = new RectShape();
//..........此处略............
}


改变图形本质通过改变Shape,ondraw绘制达到目的,实例如下:

@Override
public IBuilder roundRect(int radius) {
this.radius = radius;
float[] radii = {radius, radius, radius, radius, radius, radius, radius, radius};
this.shape = new RoundRectShape(radii, null, null);
return this;
}


这里的Builder模式运用让我眼前一亮,原来还可以这样O(∩_∩)O哈哈~,一个类实现三个借口,每个借口的函数返回可以是不同的接口,这样有个好处就是当你.xx()列出来的方法只会列出接口对应的和Builder自定义的方法,而不会完全列出builder含有的方法

public static interface IShapeBuilder {
//...........此处略...........
public IConfigBuilder beginConfig();
}
public interface IConfigBuilder {
//...........此处略...........
public IShapeBuilder endConfig();
}

public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder {

//...............此处略........................

@Override
public IConfigBuilder beginConfig() {
return this;
}

@Override
public IShapeBuilder endConfig() {
return this;
}
}


接着再来看TextDrawable的onDraw绘制方法:

@Override
public void draw(Canvas canvas) {
super.draw(canvas);
Rect r = getBounds();

// 如果边框大小大于0则绘制边框
if (borderThickness > 0) {
drawBorder(canvas);
}

int count = canvas.save();
canvas.translate(r.left, r.top);

// 绘制文字
int width = this.width < 0 ? r.width() : this.width;
int height = this.height < 0 ? r.height() : this.height;
int fontSize = this.fontSize < 0 ? (Math.min(width, height) / 2) : this.fontSize;
textPaint.setTextSize(fontSize);
canvas.drawText(text, width / 2, height / 2 - ((textPaint.descent() + textPaint.ascent()) / 2), textPaint);

canvas.restoreToCount(count);

}


基本的绘制方法就不提了,这里值得一说也就文字绘制的位置计算,当你了解了Paint的一下几个属性,想必你就能更容易理解了。

1.基准点是baseline(单行)
2.Paint.ascent:是baseline之上至字符最高处的距离
3.Paint.descent:是baseline之下至字符最低处的距离
4.Paint.leading:是上一行字符的descent到下一行的ascent之间的距离,也就是相邻行间的空白距离
5.Paint.top:是指的是最高字符到baseline的值,即ascent的最大值
6.Paint.bottom:是指最低字符到baseline的值,即descent的最大值


小结:看完这个项目,学到了两点知识:builder模式的另一种优雅实现和画笔绘制计算中心点

参考资料:http://www.zybang.com/question/bd3d73c504008384be0ec0d1daa33bec.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: