Android实际开发问题10_自定义TextBasicView
2016-05-27 16:09
543 查看
代码已经上传github(github会不定期上传各种初步研究的自定义view)
GIthub地址:https://github.com/EveSum/cView
之所以要重新设计一个Textview,是因为有的时候我们仅仅只需要一个简单的Textview,不需要多复杂的,这样节省内存资源,而且还可以从中学会如何绘制各种view
绘制单行文本使用canvas.drawText
绘制多行文本使用StaticLayout.
文字的距离Paint.FontMetricsInt
package com.caoxide.cutils.component;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.caoxide.cutils.R;
/**
* @author cxd
* @ClassName: com.caoxide.cutils.component
* @Description: 自定义文本控件
* @date 2016/5/26
*/
public class TextBasicView extends View {
//文本
private String cText;
//文本颜色
private int cTextColor;
//文本大小
private int cTextSize;
//文本对齐方式
private int cTextAligin;
//类型
private int lineType;
//画笔
private Paint mPaint;
//画笔距离
private Paint.FontMetricsInt anInt;
//文本画笔(仅在lineType==3时有效)
private TextPaint textPaint;
//多行容器(仅在lineType==3时有效)
private StaticLayout staticLayout;
public TextBasicView(Context context) {
super(context);
init(null, 0);
}
public TextBasicView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public TextBasicView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
/**
* 初始化
*
* @param attrs
* @param defStyleAttr
*/
private void init(AttributeSet attrs, int defStyleAttr) {
//获得属性
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.TextBasicView, defStyleAttr, 0);
//获取文本
cText = typedArray.getString(R.styleable.TextBasicView_cText);
//获取颜色值
cTextColor = typedArray.getColor(R.styleable.TextBasicView_cTextColor, Color.BLUE);
//获取字体大小
cTextSize = typedArray.getDimensionPixelSize(R.styleable.TextBasicView_cTextSize,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
//获取文本对齐方式
cTextAligin = typedArray.getInt(R.styleable.TextBasicView_cTextAlign, 1);
//获取行数类型
lineType = typedArray.getInt(R.styleable.TextBasicView_lineType, 3);
//记住属性
typedArray.recycle();
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
if (lineType == 3) {
if (textPaint == null) {
textPaint = new TextPaint();
//设置画笔大小
textPaint.setTextSize(cTextSize);
//设置画笔颜色
textPaint.setColor(cTextColor);
}
} else {
if (mPaint == null) {
mPaint = new Paint();
//设置画笔大小
mPaint.setTextSize(cTextSize);
//设置画笔颜色
mPaint.setColor(cTextColor);
//设置文本方向
mPaint.setTextAlign(cTextAligin == 1 ? Paint.Align.LEFT : cTextAligin == 2 ? Paint.Align.RIGHT : Paint.Align.CENTER);
}
if (anInt == null) {
anInt = mPaint.getFontMetricsInt();
}
}
}
/**
* 获取多行布局
*
* @return
*/
private StaticLayout getStaticLayout() {
if (staticLayout == null) {
staticLayout = new StaticLayout(cText, textPaint, getWidth() - getPaddingLeft() - getPaddingRight(),
cTextAligin == 1 ? Layout.Alignment.ALIGN_NORMAL : cTextAligin == 2 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
1.2f, 0, false);
}
return staticLayout;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
initPaint();
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width;
int height;
//获取控件宽度
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
float showTextLength = mPaint.measureText(cText);
width = Math.min((int) showTextLength, widthSize);
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
if (lineType == 1) {//单行显示
height = anInt.bottom - anInt.ascent + getPaddingTop() + getPaddingBottom();
} else if (lineType == 2) {//两行显示
height = 2 * anInt.bottom - anInt.ascent - anInt.top + getPaddingTop() + getPaddingBottom();
} else {//多行显示
height = getStaticLayout().getHeight() + getPaddingBottom() + getPaddingTop();
}
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
initPaint();
int width = 0;
if (cTextAligin == 1) {
width = getPaddingLeft();
} else if (cTextAligin == 2) {
width = getWidth() - getPaddingRight();
} else {
width = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2;
}
if (lineType == 1) {//单行显示
String showText = getShowText(mPaint, cText);
//获取基准线的高度(去除文本上面的音标区域,即不使用top,使用ascent)
int height = (getHeight() - anInt.bottom + anInt.ascent) / 2 - anInt.ascent;
//书写文字
canvas.drawText(showText, width, height, mPaint);
} else if (
4000
lineType == 2) {//两行显示
//获取第一行显示文本
String showText1 = getShowText(mPaint, cText, false);
//获取第一行基准线的高度
int height1 = (getHeight() + anInt.ascent + anInt.top) / 2 - anInt.bottom - anInt.ascent;
//书写文字
canvas.drawText(showText1, width, height1, mPaint);
if (showText1.length() < cText.length()) {
String str = cText.substring(showText1.length());
String showText2 = getShowText(mPaint, str);//获取文字区域
//获取第二行基准线的高度
int height2 = (getHeight() - anInt.ascent - anInt.top) / 2;
//书写文字
canvas.drawText(showText2, width, height2, mPaint);
}
} else if (lineType == 3) {//多行显示
canvas.translate(getPaddingLeft(), getPaddingTop());
getStaticLayout().draw(canvas);
}
}
/**
* 获取显示文本
*
* @param mPaint 画笔
* @param text 要书写的文本
* @return 显示文本
*/
private String getShowText(Paint mPaint, String text) {
return getShowText(mPaint, text, true);
}
/**
* 获取显示文本
*
* @param mPaint 画笔
* @param text 要书写的文本
* @param isEn 是否省略
* @return 显示文本
*/
private String getShowText(Paint mPaint, String text, boolean isEn) {
//获取文本显示区域
int textRextWidth = getWidth() - getPaddingLeft() - getPaddingRight();
//获取要书写文字的宽度
float textWidth = mPaint.measureText(text);
//书写文字宽度在显示区域内,直接书写即可
if (textWidth < textRextWidth) {
return text;
}
//获取省略号的宽度
if (isEn) {
float enWidth = mPaint.measureText("...");
//获取除省略号的可显示区域
textRextWidth -= enWidth;
}
//获取一个汉字的宽度
float ziWidth = mPaint.measureText("字");
//判断书写文字是否绝大部分为汉字,误差为每十个字一个不是
if (ziWidth * text.length() <= textWidth + text.length() / 10 * ziWidth) {
//获取显示文字宽度
int len = (int) (textRextWidth / ziWidth);
int dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));
while (dev > ziWidth) {
len += dev / ziWidth;
dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));
}
return text.substring(0, len - 1) + (isEn ? "..." : "");
} else {
int len = (int) (textRextWidth * text.length() / textWidth);
if (len < 1) {
return "...";
}
int len_ = len - 1;
int dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));
int dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));
while (dev > 0 || dev_ < 0) {
if (dev > 0) {
int l = (int) (dev * text.length() / textWidth);
if (l == 0) {
l = 1;
}
len += l;
len_ = len - 1;
} else {
int l = (int) (dev_ * text.length() / textWidth);
if (l == 0) {
l = 1;
}
len_ -= l;
len = len_ + 1;
}
dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));
dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));
}
return text.substring(0, len_ - 1) + (isEn ? "..." : "");
}
}
}
GIthub地址:https://github.com/EveSum/cView
之所以要重新设计一个Textview,是因为有的时候我们仅仅只需要一个简单的Textview,不需要多复杂的,这样节省内存资源,而且还可以从中学会如何绘制各种view
绘制单行文本使用canvas.drawText
绘制多行文本使用StaticLayout.
文字的距离Paint.FontMetricsInt
package com.caoxide.cutils.component;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.caoxide.cutils.R;
/**
* @author cxd
* @ClassName: com.caoxide.cutils.component
* @Description: 自定义文本控件
* @date 2016/5/26
*/
public class TextBasicView extends View {
//文本
private String cText;
//文本颜色
private int cTextColor;
//文本大小
private int cTextSize;
//文本对齐方式
private int cTextAligin;
//类型
private int lineType;
//画笔
private Paint mPaint;
//画笔距离
private Paint.FontMetricsInt anInt;
//文本画笔(仅在lineType==3时有效)
private TextPaint textPaint;
//多行容器(仅在lineType==3时有效)
private StaticLayout staticLayout;
public TextBasicView(Context context) {
super(context);
init(null, 0);
}
public TextBasicView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public TextBasicView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
/**
* 初始化
*
* @param attrs
* @param defStyleAttr
*/
private void init(AttributeSet attrs, int defStyleAttr) {
//获得属性
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.TextBasicView, defStyleAttr, 0);
//获取文本
cText = typedArray.getString(R.styleable.TextBasicView_cText);
//获取颜色值
cTextColor = typedArray.getColor(R.styleable.TextBasicView_cTextColor, Color.BLUE);
//获取字体大小
cTextSize = typedArray.getDimensionPixelSize(R.styleable.TextBasicView_cTextSize,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
//获取文本对齐方式
cTextAligin = typedArray.getInt(R.styleable.TextBasicView_cTextAlign, 1);
//获取行数类型
lineType = typedArray.getInt(R.styleable.TextBasicView_lineType, 3);
//记住属性
typedArray.recycle();
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
if (lineType == 3) {
if (textPaint == null) {
textPaint = new TextPaint();
//设置画笔大小
textPaint.setTextSize(cTextSize);
//设置画笔颜色
textPaint.setColor(cTextColor);
}
} else {
if (mPaint == null) {
mPaint = new Paint();
//设置画笔大小
mPaint.setTextSize(cTextSize);
//设置画笔颜色
mPaint.setColor(cTextColor);
//设置文本方向
mPaint.setTextAlign(cTextAligin == 1 ? Paint.Align.LEFT : cTextAligin == 2 ? Paint.Align.RIGHT : Paint.Align.CENTER);
}
if (anInt == null) {
anInt = mPaint.getFontMetricsInt();
}
}
}
/**
* 获取多行布局
*
* @return
*/
private StaticLayout getStaticLayout() {
if (staticLayout == null) {
staticLayout = new StaticLayout(cText, textPaint, getWidth() - getPaddingLeft() - getPaddingRight(),
cTextAligin == 1 ? Layout.Alignment.ALIGN_NORMAL : cTextAligin == 2 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
1.2f, 0, false);
}
return staticLayout;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
initPaint();
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width;
int height;
//获取控件宽度
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
float showTextLength = mPaint.measureText(cText);
width = Math.min((int) showTextLength, widthSize);
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
if (lineType == 1) {//单行显示
height = anInt.bottom - anInt.ascent + getPaddingTop() + getPaddingBottom();
} else if (lineType == 2) {//两行显示
height = 2 * anInt.bottom - anInt.ascent - anInt.top + getPaddingTop() + getPaddingBottom();
} else {//多行显示
height = getStaticLayout().getHeight() + getPaddingBottom() + getPaddingTop();
}
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
initPaint();
int width = 0;
if (cTextAligin == 1) {
width = getPaddingLeft();
} else if (cTextAligin == 2) {
width = getWidth() - getPaddingRight();
} else {
width = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2;
}
if (lineType == 1) {//单行显示
String showText = getShowText(mPaint, cText);
//获取基准线的高度(去除文本上面的音标区域,即不使用top,使用ascent)
int height = (getHeight() - anInt.bottom + anInt.ascent) / 2 - anInt.ascent;
//书写文字
canvas.drawText(showText, width, height, mPaint);
} else if (
4000
lineType == 2) {//两行显示
//获取第一行显示文本
String showText1 = getShowText(mPaint, cText, false);
//获取第一行基准线的高度
int height1 = (getHeight() + anInt.ascent + anInt.top) / 2 - anInt.bottom - anInt.ascent;
//书写文字
canvas.drawText(showText1, width, height1, mPaint);
if (showText1.length() < cText.length()) {
String str = cText.substring(showText1.length());
String showText2 = getShowText(mPaint, str);//获取文字区域
//获取第二行基准线的高度
int height2 = (getHeight() - anInt.ascent - anInt.top) / 2;
//书写文字
canvas.drawText(showText2, width, height2, mPaint);
}
} else if (lineType == 3) {//多行显示
canvas.translate(getPaddingLeft(), getPaddingTop());
getStaticLayout().draw(canvas);
}
}
/**
* 获取显示文本
*
* @param mPaint 画笔
* @param text 要书写的文本
* @return 显示文本
*/
private String getShowText(Paint mPaint, String text) {
return getShowText(mPaint, text, true);
}
/**
* 获取显示文本
*
* @param mPaint 画笔
* @param text 要书写的文本
* @param isEn 是否省略
* @return 显示文本
*/
private String getShowText(Paint mPaint, String text, boolean isEn) {
//获取文本显示区域
int textRextWidth = getWidth() - getPaddingLeft() - getPaddingRight();
//获取要书写文字的宽度
float textWidth = mPaint.measureText(text);
//书写文字宽度在显示区域内,直接书写即可
if (textWidth < textRextWidth) {
return text;
}
//获取省略号的宽度
if (isEn) {
float enWidth = mPaint.measureText("...");
//获取除省略号的可显示区域
textRextWidth -= enWidth;
}
//获取一个汉字的宽度
float ziWidth = mPaint.measureText("字");
//判断书写文字是否绝大部分为汉字,误差为每十个字一个不是
if (ziWidth * text.length() <= textWidth + text.length() / 10 * ziWidth) {
//获取显示文字宽度
int len = (int) (textRextWidth / ziWidth);
int dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));
while (dev > ziWidth) {
len += dev / ziWidth;
dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));
}
return text.substring(0, len - 1) + (isEn ? "..." : "");
} else {
int len = (int) (textRextWidth * text.length() / textWidth);
if (len < 1) {
return "...";
}
int len_ = len - 1;
int dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));
int dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));
while (dev > 0 || dev_ < 0) {
if (dev > 0) {
int l = (int) (dev * text.length() / textWidth);
if (l == 0) {
l = 1;
}
len += l;
len_ = len - 1;
} else {
int l = (int) (dev_ * text.length() / textWidth);
if (l == 0) {
l = 1;
}
len_ -= l;
len = len_ + 1;
}
dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));
dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));
}
return text.substring(0, len_ - 1) + (isEn ? "..." : "");
}
}
}
相关文章推荐
- Android自定义控件常用方法总结
- Android之权限检查(解决未获取用户权限允许)
- Android调用系统相机拍照并存入相册
- android studio报错:ClassLoader referenced unknown path: /data/app/xxxx-1/lib/arm64
- android播放开机动画方法
- Android学习笔记01——TextView
- Android 自定义控件(二)
- Android画图Path的使用
- Android应用打破65K方法数限制Conversion to Dalvik format failed: Unable to execute dex: method ID not in 65536
- Android中dp和px之间进行转换的代码
- Android EditView用法小结
- Android Library项目注意事项
- Android 自定义控件---SpreadView
- android api 中setVisibility( )的用法(可显示或隐藏布局或控件...)
- Android 5.0+ 解析(五)FloatingActionButton控件
- CaysnPrinter打印示例 - Sample1 For Android
- Android 5.0+ 解析(四)Toolbar控件
- Android 探究 LayoutInflater setFactory
- android关机流程-framework部分
- Android 5.0+ 解析(三)Palette类