如何使多个文本框对齐文本在 Android TextView 向右对齐

Android TextView两端对齐解决办法
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android TextView两端对齐解决办法的相关资料,需要的朋友可以参考下
Android TextView两端对齐解决办法
今天遇到一个关于TextView文字两端对齐其实方案,大家都知道原生控件是不能满足我们的需求的,因此需要自定义View
下面看下效果图
package com.example.VerticalMarqueeTextView.
import android.content.C
import android.graphics.C
import android.graphics.P
import android.text.TextP
import android.text.TextU
import android.util.AttributeS
import android.view.ViewG
import android.view.ViewTreeO
import android.widget.TextV
* Created by John on .
public class WordAlignTextView extends TextView {
private float textS
private float textLineH
private int lineDrawW
private char[] textCharA
private float singleWordW
//每个字符的空隙
private float lineSpacingE
private boolean isFirst =
public WordAlignTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
initTextInfo();
public WordAlignTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
public WordAlignTextView(Context context) {
this(context, null, 0);
public void initTextInfo() {
textSize = getTextSize();
//获取线的高度
textLineHeight = getLineHeight();
right = getRight();
y = getTop();
// 要画的宽度
int drawTotalWidth = right -
String text = getText().toString();
if (!TextUtils.isEmpty(text) && isFirst) {
textCharArray = text.toCharArray();
TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.density = getResources().getDisplayMetrics().
mTextPaint.setTextSize(textSize);
// 获取单个单词的的宽度
singleWordWidth = mTextPaint.measureText("一") + lineSpacingE
// 每行可以放多少个字符
lineDrawWords = (int) (drawTotalWidth / singleWordWidth);
int length = textCharArray.
lines = length / lineDrawW
if ((length % lineDrawWords) & 0) {
lines = lines + 1;
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
int totalHeight = (int) (lines*textLineHeight+textLineHeight*2 + getPaddingBottom()+getPaddingTop()+layoutParams.bottomMargin+layoutParams.topMargin);
setHeight(totalHeight);
protected void onDraw(Canvas canvas) {
bottom = getBottom();
int drawTotalLine =
if(maxLine!=0&&drawTotalLine&maxLine){
drawTotalLine = maxL
for (int i = 0; i & drawTotalL i++) {
int length = textCharArray.
int mLeft =
// 第i+1行开始的字符index
int startIndex = (i * 1) * lineDrawW
// 第i+1行结束的字符index
int endTextIndex = startIndex + lineDrawW
if (endTextIndex & length) {
endTextIndex =
y += textLineH
y += textLineH
for (; startIndex & endTextI startIndex++) {
char c = textCharArray[startIndex];
if (c == ' ') {
c = '\u3000';
} else if (c & '\177') {
c = (char) (c + 65248);
canvas.drawText(String.valueOf(c), mLeft, y, getPaint());
mLeft += singleWordW
} catch (Exception e) {
e.printStackTrace();
public void setMaxLines(int max){
this.maxLine =
public void setLineSpacingExtra(int lineSpacingExtra){
this.lineSpacingExtra = lineSpacingE
* 判断是否为中文
public static boolean containChinese(String string){
boolean flag =
for (int i = 0; i & string.length(); i++) {
char c = string.charAt(i);
if ((c &= 0x4e00) && (c &= 0x9FA5)) {
public static String ToDBC(String input) {
// 导致TextView异常换行的原因:安卓默认数字、字母不能为第一行以后每行的开头字符,因为数字、字母为半角字符
// 所以我们只需要将半角字符转换为全角字符即可
char c[] = input.toCharArray();
for (int i = 0; i & c. i++) {
if (c[i] == ' ') {
c[i] = '\u3000';
} else if (c[i] & '\177') {
c[i] = (char) (c[i] + 65248);
return new String(c);
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具自定义View显示文本
网上就有达人采用自定义View来解决这个问题,我做了实验并总结了一下:
自定义View的步骤:
1)继承View类或其子类,例子继承了TextView类;
2)写构造函数,通过XML获取属性(这一步中可以自定义属性,见例程);
3)重写父类的某些函数,一般都是
自定义View显示文本
网上就有达人采用自定义View来解决这个问题,我做了实验并总结了一下:
自定义View的步骤:
1)继承View类或其子类,例子继承了TextView类;
2)写构造函数,通过XML获取属性(这一步中可以自定义属性,见例程);
3)重写父类的某些函数,一般都是以on开头的函数,例子中重写了onDraw()和onMeasure()函数;
=========================StartCustomTextView.java=============================
public class StartCustomTextView extends TextView {
int m_iTextH //文本的高度
int m_iTextW//文本的宽度
private Paint mPaint =
private String string="";
private float LineSpace = 0;//行间距
private int left_M
private int right_M
private int bottom_M
public StartCustomTextView(Context context, AttributeSet set)
super(context,set);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);
int width = displayMetrics.widthP
left_Margin = 29;
right_Margin = 29;
bottom_Margin = 29;
width = width - left_Margin -right_M
float textsize = typedArray.getDimension(R.styleable.CYTextView_textSize, 34);
int textcolor = typedArray.getColor(R.styleable.CYTextView_textColor, getResources().getColor(R.color.white));
float linespace = typedArray.getDimension(R.styleable.CYTextView_lineSpacingExtra, 15);
int typeface = typedArray.getColor(R.styleable.CYTextView_typeface, 0);
typedArray.recycle();
//设置 CY TextView的宽度和行间距
m_iTextWidth=
LineSpace=
// 构建paint对象
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(textcolor);
mPaint.setTextSize(textsize);
switch(typeface){
mPaint.setTypeface(Typeface.DEFAULT);
mPaint.setTypeface(Typeface.SANS_SERIF);
mPaint.setTypeface(Typeface.SERIF);
mPaint.setTypeface(Typeface.MONOSPACE);
mPaint.setTypeface(Typeface.DEFAULT);
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
int w = 0;
int istart = 0;
int m_iFontH
int m_iRealLine=0;
m_String=new Vector();
FontMetrics fm = mPaint.getFontMetrics();
m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineS//计算字体高度(字体高度+行间距)
for (int i = 0; i & string.length(); i++)
ch = string.charAt(i);
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);
if (ch == '\n'){
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
istart = i + 1;
w += (int) (Math.ceil(widths[0]));
if (w & m_iTextWidth){
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
if (i == (string.length() - 1)){
m_iRealLine++;
m_String.addElement(string.substring(istart, string.length()));
m_iTextHeight=m_iRealLine*m_iFontHeight+2;
canvas.setViewport(m_iTextWidth, m_iTextWidth);
for (int i = 0, j = 0; i & m_iRealL i++, j++)
canvas.drawText((String)(m_String.elementAt(i)), x,
y+m_iFontHeight * j, mPaint);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
this.setMeasuredDimension(measuredWidth, measuredHeight);
LayoutParams layout = new LinearLayout.LayoutParams(measuredWidth,measuredHeight);
layout.leftMargin= left_M
layout.rightMargin= right_M
layout.bottomMargin= bottom_M
this.setLayoutParams(layout);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
private int measureHeight(int measureSpec)
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
initHeight();
int result = m_iTextH
if (specMode == MeasureSpec.AT_MOST){
// Calculate the ideal size of your
// control within this maximum size.
// If your control fills the available
// space return the outer bound.
result = specS
}else if (specMode == MeasureSpec.EXACTLY){
// If your control can fit within these bounds return that value.
result = specS
private void initHeight()
//设置 CY TextView的初始高度为0
m_iTextHeight=0;
//大概计算 CY TextView所需高度
FontMetrics fm = mPaint.getFontMetrics();
int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineS
int line=0;
int istart=0;
for (int i = 0; i & string.length(); i++)
char ch = string.charAt(i);
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);
if (ch == '\n'){
istart = i + 1;
w += (int) (Math.ceil(widths[0]));
if (w & m_iTextWidth){
if (i == (string.length() - 1)){
m_iTextHeight=(line)*m_iFontHeight+2;
private int measureWidth(int measureSpec)
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST){
// Calculate the ideal size of your control
// within this maximum size.
// If your control fills the available space
// return the outer bound.
result = specS
}else if (specMode == MeasureSpec.EXACTLY){
// If your control can fit within these bounds return that value.
result = specS
public void SetText(String text)
// requestLayout();
// invalidate();
=======================attrs.xml===============================
该文件是自定义的属性,放在工程的res/values下
&resources&
&attr name="textwidth" format="integer"/&
&attr name="typeface"&
&enum name="normal" value="0"/&
&enum name="sans" value="1"/&
&enum name="serif" value="2"/&
&enum name="monospace" value="3"/&
&declare-styleable name="CYTextView"&
&attr name="textwidth" /&
&attr name="textSize" format="dimension"/&
&attr name="textColor" format="reference|color"/&
&attr name="lineSpacingExtra" format="dimension"/&
&attr name="typeface" /&
&/declare-styleable&
&/resources&
=======================main.xml==========================
&?xml version="1.0" encoding="utf-8"?&
&ScrollView
xmlns:Android="/apk/res/android"
Android:layout_width="320px"
Android:layout_height="320px"
Android:background="#ffffffff"
&LinearLayout
xmlns:Android="/apk/res/android"
Android:orientation="vertical"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"&
&com.cy.CYTextView.CYTextView
xmlns:cy="/apk/res/ com.cy.CYTextView "
Android:id="@+id/mv"
Android:layout_height="wrap_content"
Android:layout_width="wrap_content"
cy :textwidth="320"
cy :textSize="24sp"
cy :textColor="#aa000000"
cy :lineSpacingExtra="15sp"
cy :typeface="serif"&
&/com. cy .CYTextView.CYTextView&
&/LinearLayout&
&/ScrollView&
蓝色代码即为自定义View,其中以cy命名空间开头的属性是自定义属性;
=======================Main.java=============================
public class Main extends Activity {
CYTextView mCYTextV
String text = "Android提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
mCYTextView = (CYTextView)findViewById(R.id.mv);
mCYTextView.SetText(text);
版权声明:本文内容由互联网用户自发贡献,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至: 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
用云栖社区APP,舒服~
【云栖快讯】阿里云数据库MySQL金融版发布,实现日志多副本同步复制,提供金融级可靠性!8月10日,阿里云数据库掌门人褚霸等大牛直播,揭开它的背后故事!赶紧报名吧&&
是根据用户的业务需求和策略,经济地自动调整其弹性计算资源的管理服务,能够在业务增长时自动增加 ECS 实例,并在...
业内领先的面向企业的一站式研发提效平台,通过项目流程管理和专项自动化提效工具,能够很好地支持互联网敏捷项目的快速...
是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有...
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...
2017杭州云栖大会火热抢票
Loading...你的位置: >
> TextView中英文排版混乱
TextView问题由来
TextView在中英文夹杂的时候,会出现自动断行的情况,相信许多人都碰见过。这是系统的一个Bug,在Android5.0以后被修复了,而5.0以下的还没有见到比较好的解决版本。
参考了网上的方法,有的朋友推荐使用全角和半角转换(没有解决问题),也有的推荐了JustifyTextView这个控件(效果也不理想)。
于是我决定自定义一个TextView来做这件事,勉强解决了问题,但是代价是失去了很多TextView自身拥有的特性,而且TextView自身做了很多缓存和优化的工作,Google强烈不建议我们去修改这个控件。
我们先来看看实现效果:
第1行:原生TextView 全是中文
第2行:原生TextView 全是英文
第3行:原生TextView,使用全角半角转换中英文夹杂
第4行:原生TextView 中英文夹杂
第5行:JustifyTextView 中英文夹杂
第6行:原生AdaptableTextView 中英文夹杂
怎么解决?
1、将text分割成多行
思路的第一步,就是将我们要设置的文本,例如”中英文夹杂testtesttesttesttesttesttesttesttesttest”这个String分割成多行保存在一个ArrayList()中。
我们可以首先获得TextView的宽度,然后根据这个宽度,把上面的String切割成多段。
由于“我”这个中文的在绘制时候,宽度比单个英文字母,例如是”m”大。所以我们一定要遍历每个字符,获得它的宽度。
* 根据控件宽度,计算得出每行的字符串
private void parseText(){
strs.clear();
int start = 0;//行起始Index
int curLineWidth = 0;//当前行宽
for (int i = 0; i & mText.length(); i++) {
char ch = mText.charAt(i);//获取当前字符
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);//获取这个字符的宽度
if (ch == '\n'){//如果是换行符,则当独一行
strs.add(mText.substring(start, i));
start = i + 1;
curLineWidth = 0;
curLineWidth += (int) (Math.ceil(widths[0]));//计算当前宽度
if (curLineWidth & mLineWidth){//直到当前行宽度大于控件宽度,截取为一行
strs.add(mText.substring(start, i));
curLineWidth = 0;
if (i == (mText.length() - 1)){//剩余的单独一行
strs.add(mText.substring(start, mText.length()));
2、使用drawText()方法,绘制出每一行
在上面的方法以后,我们就获得了每一行字符串了,剩下的工作就是用drawText()把每一行都绘制出来就可以了。另外还要注意一些,例如如果超出了maxLines,我们可以手动绘制一个省略号;还有padding的设置问题。
public void draw(Canvas canvas) {
int lines = mMaxLines & 0 && mMaxLines &= strs.size() ? mMaxLines : strs.size();
for (int i = 0; i & i++) {
String text = strs.get(i);
//如果是最大行的最后一行但不是真实的最后一行则自动添加省略号
if(i == lines - 1 && i & strs.size() - 1)
text = text.substring(0, text.length() - 3) + &...&;
canvas.drawText(text, getPaddingLeft(), getPaddingTop()+mPaint.getTextSize() + mLineHeight * i, mPaint);
3、重写TextView的onDraw()方法
简单来说,只要在ondraw()方法里面,调用我们自定义的draw()方法,绘制出文本即可。
@SuppressLint(&NewApi&)
protected void onDraw(Canvas canvas) {
getAdaptableText();
if(mIsDirty) {
mIsDirty =
String text = getText().toString();
int maxLines = getMaxLines();
if(!mAdaptableText.getText().equals(text))
mAdaptableText.setText(text);
if(mAdaptableText.getMaxLines() != maxLines)
mAdaptableText.setMaxLines(maxLines);
mAdaptableText.draw(canvas);
TextView的这个Bug,几乎在所有的app都存在(微信什么的),也就可以看出,貌似没有很好的解决方法。
如果使用上面的自定义控件,看似解决了问题,其实带来TextView效率的严重下降,所有也强烈不建议在项目之中使用它(如果你们的app不追求效率又是另外一回事了)。
转载请注明: &
与本文相关的文章3444人阅读
Android(279)
android:gravity=&right&。gravity属性是组件内容的对齐方式的设置属性。其他左对齐,居中什么的,都是这个。注意区分layout_gravity,是组件本身相对于其父布局的对齐方式。比如让textview右对齐。android:layout_gravity=&right&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:319629次
积分:5800
积分:5800
排名:第4356名
原创:174篇
转载:590篇
评论:99条1087人阅读
Android自定义View(2)
& & & & Android原生的TextView在显示文字时,右端可能会因为 不够一个文字 或者 标点符号 的问题而参差不齐。这里自定义一个JustifyTextView,解决右端不能对齐的问题。如下图所示,上方的TextView为自定义的,下方为原生的。
开发环境: &AndroidStudio 2.3.2 & & &
直接上代码,下面是自定义的JustifyTextView.java
package com.katherine.du.justifytextviewdemo.
import android.content.C
import android.graphics.C
import android.text.L
import android.text.StaticL
import android.text.TextP
import android.util.AttributeS
import android.widget.TextV
* Created by du on 17/7/30.
public class JustifyTextView extends TextView {
private int mLineY = 0;//总行高
private int mViewW//TextView的总宽度
private TextP
public JustifyTextView(Context context) {
super(context);
public JustifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
public JustifyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
private void init() {
paint = getPaint();
paint.setColor(getCurrentTextColor());
paint.drawableState = getDrawableState();
protected void onDraw(Canvas canvas) {
mViewWidth = getMeasuredWidth();//获取textview的实际宽度
mLineY += getTextSize();
String text = getText().toString();
Layout layout = getLayout();
int lineCount = layout.getLineCount();
for (int i = 0; i & lineC i++) {//每行循环
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
String lineText = text.substring(lineStart, lineEnd);//获取TextView每行中的内容
if (needScale(lineText)) {
if (i == lineCount - 1) {//最后一行不需要重绘
canvas.drawText(lineText, 0, mLineY, paint);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, paint);
drawScaleText(canvas, lineText, width);
canvas.drawText(lineText, 0, mLineY, paint);
mLineY += getLineHeight();//写完一行以后,高度增加一行的高度
* 重绘此行.
* @param canvas
* @param lineText
该行所有的文字
* @param lineWidth 该行每个文字的宽度的总和
private void drawScaleText(Canvas canvas, String lineText, float lineWidth) {
float x = 0;
if (isFirstLineOfParagraph(lineText)) {
String blanks = &
canvas.drawText(blanks, x, mLineY, paint);
float width = StaticLayout.getDesiredWidth(blanks, paint);
lineText = lineText.substring(3);
//比如说一共有5个字,中间有4个间隔,
//那就用整个TextView的宽度 - 5个字的宽度,
//然后除以4,填补到这4个空隙中
float interval = (mViewWidth - lineWidth) / (lineText.length() - 1);
for (int i = 0; i & lineText.length(); i++) {
String character = String.valueOf(lineText.charAt(i));
float cw = StaticLayout.getDesiredWidth(character, paint);
canvas.drawText(character, x, mLineY, paint);
x += (cw + interval);
* 判断是不是段落的第一行.
* 一个汉字相当于一个字符,此处判断是否为第一行的依据是:
* 字符长度大于3且前两个字符为空格
* @param lineText 该行所有的文字
private boolean isFirstLineOfParagraph(String lineText) {
return lineText.length() & 3 && lineText.charAt(0) == ' ' && lineText.charAt(1) == ' ';
* 判断需不需要缩放.
* @param lineText 该行所有的文字
* @return true 该行最后一个字符不是换行符
false 该行最后一个字符是换行符
private boolean needScale(String lineText) {
if (lineText.length() == 0) {
return lineText.charAt(lineText.length() - 1) != '\n';
然后是布局文件activity_main.xml
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical&
tools:context=&com.katherine.du.justifytextviewdemo.MainActivity&&
&com.katherine.du.justifytextviewdemo.view.JustifyTextView
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:layout_marginLeft=&15dp&
android:layout_marginRight=&15dp&
android:layout_marginTop=&15dp&
android:lineSpacingExtra=&5dp&
android:text=&听见,冬天的离开,我在某年某月,醒过来,我想,我等,我期待,未来却不能因此安排,阴天,傍晚,车窗外,未来有一个人在等待,向左向右向前看,爱要拐几个弯才来。。。。。& /&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_marginLeft=&15dp&
android:layout_marginRight=&15dp&
android:layout_marginTop=&15dp&
android:lineSpacingExtra=&5dp&
android:text=&听见,冬天的离开,我在某年某月,醒过来,我想,我等,我期待,未来却不能因此安排,阴天,傍晚,车窗外,未来有一个人在等待,向左向右向前看,爱要拐几个弯才来。。。。。& /&
&/LinearLayout&
主Activity没写什么。。。MainActivity.java
package com.katherine.du.
import android.app.A
import android.os.B
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
项目链接:
项目链接:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:9895次
排名:千里之外
原创:24篇
(1)(2)(1)(3)(2)(3)(2)(1)(4)(1)(1)(1)(4)(1)(1)(4)

我要回帖

更多关于 css 向右对齐 的文章

 

随机推荐