赞
踩
第一次写东西,内心小紧张,又不知道怎么写,尽量把遇到的问题和解决思路说清楚,写的不好请见谅。
项目有一个需求,很简单,就是一个recyclerview,item里面是两个textview。一个TextView显示的字符串包含圆角、半角和中、英文以及数字。
想起来简单,但是一显示就出问题了。右侧的TextView因为自动换行的问题显示错乱,真不行。至于原因,网上有很多介绍,下面就讲一下解决过程。
和大多数人一样,发现这个问题,立马找百度看看有可以直接用的,大致分为两种:
1)手动拆分字符串:不管是自定义view还是在view预加载时,手动对要显示的字符串进行拆分,添加换行符“\n”后再显示。
2)自定义view,挨个画每个字符,如果排不下就换行
以这两种方式,都找到了可以直接用代码。我还是比较谨慎,先写了demo看了,效果还行,才往项目里写,心想这下总解决了哇,然而高兴得太早了。demo只是给了个TextView,可是项目是RecyclerView,一运行,程序能跑起来的就不错了,还有的直接OOM,于是心灰意冷。
既然百度不到,就只有自己动手了。解决思路采用的是自定义view,挨个画字符。原理很简单,直接上代码:
- public class MyTextView extends View {
- //内容填充画笔
- private Paint contentPaint;
- //标准的字体颜色
- private String contentNormalColor = "#737373";
- //有焦点的字体颜色
- private String contentFocuedColor = "#333333";
- //控件宽度
- private int viewWidth = 0;
- //控件高度
- private int viewHeight = 0;
- //标准的字的样式
- public static final int TEXT_TYPE_NORMAL = 1;
- //控件获取焦点的时候进行的处理
- public static final int TEXT_TYPE_FOCUED = 2;
- //默认是标准的样式
- private int currentTextType = TEXT_TYPE_NORMAL;
- //默认当前的颜色
- private String textColor = "#333333";
- //字体大小
- private int textSize = 40;
- //内容
- private String mText = "测试的文字信息";
- //最小view高度
- private float minHeight = 0;
- //最小view宽度
- private float minWidth = 0;
- //行间距
- private float lineSpace;
- //最大行数
- private int maxLines = 0;
- //文字测量工具
- private Paint.FontMetricsInt textFm;
- ///真实的行数
- private int realLines;
- //当前显示的行数
- private int line;
- //在末尾是否显示省略号
- private boolean showEllipsise;
-
- //文字显示区的宽度
- private int textWidth;
- //单行文字的高度
- private int signleLineHeight;
- private int mPaddingLeft,mPaddingRight,mPaddingTop,mPaddingBottom;
- /**
- * 省略号
- **/
- private String ellipsis = "...";
- public MyTextView(Context context) {
- this(context,null);
- }
-
- public MyTextView(Context context, AttributeSet attrs) {
- this(context, attrs,0);
- }
-
- public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initAttr(context,attrs);
- init();
- }
- private boolean isFristload;
-
- /**
- * 初始化
- */
- private void init() {
- contentPaint = new Paint();
- contentPaint.setTextSize(textSize);
- contentPaint.setAntiAlias(true);
- contentPaint.setStrokeWidth(2);
- contentPaint.setColor(Color.parseColor(textColor));
- contentPaint.setTextAlign(Paint.Align.LEFT);
- textFm = contentPaint.getFontMetricsInt();
- signleLineHeight=Math.abs(textFm.top-textFm.bottom);
- }
-
- /**
- * 初始化属性
- * @param context
- * @param attrs
- */
- private void initAttr(Context context,AttributeSet attrs) {
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);
- mPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.MyTextView_paddingLeft, 0);
- mPaddingRight = typedArray.getDimensionPixelSize(R.styleable.MyTextView_paddingRight, 0);
- mPaddingTop = typedArray.getDimensionPixelSize(R.styleable.MyTextView_paddingTop, 0);
- mPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.MyTextView_paddingBottom, 0);
-
- mText = typedArray.getString(R.styleable.MyTextView_text);
- textColor = typedArray.getString(R.styleable.MyTextView_textColor);
- if(textColor==null){
- textColor="#000000";
- }
- textSize = typedArray.getDimensionPixelSize(R.styleable.MyTextView_textSize, 50);
- lineSpace = typedArray.getInteger(R.styleable.MyTextView_lineSpacing, 0);
- typedArray.recycle();
- }
-
- public void setText(String ss){
- this.mText=ss;
- invalidate();
- }
-
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec,heightMeasureSpec);
- viewWidth=getMeasuredWidth();
- textWidth=viewWidth-mPaddingLeft-mPaddingRight;
- viewHeight= (int) getViewHeight();
- setMeasuredDimension(viewWidth, viewHeight);
- }
-
- private float getViewHeight() {
- char[] textChars=mText.toCharArray();
- float ww=0.0f;
- int count=0;
- StringBuilder sb=new StringBuilder();
- for(int i=0;i<textChars.length;i++){
- float v = contentPaint.measureText(textChars[i] + "");
- if(ww+v<=textWidth){
- sb.append(textChars[i]);
- ww+=v;
- }
- else{
- count++;
- sb=new StringBuilder();
- ww=0.0f;
- ww+=v;
- sb.append(textChars[i]);
- }
- }
- if(sb.toString().length()!=0){
- count++;
- }
- return count*signleLineHeight+lineSpace*(count-1)+mPaddingBottom+mPaddingTop;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- drawText(canvas);
- }
-
- /**
- * 循环遍历画文字
- * @param canvas
- */
- private void drawText(Canvas canvas) {
-
- char[] textChars=mText.toCharArray();
- float ww=0.0f;
- float startL=0.0f;
- float startT=0.0f;
- startL+=mPaddingLeft;
- startT+=mPaddingTop+signleLineHeight/2+ (textFm.bottom-textFm.top)/2 - textFm.bottom;
- StringBuilder sb=new StringBuilder();
-
- for(int i=0;i<textChars.length;i++){
- float v = contentPaint.measureText(textChars[i] + "");
- if(ww+v<=textWidth){
- sb.append(textChars[i]);
- ww+=v;
- }
- else{
- canvas.drawText(sb.toString(),startL,startT,contentPaint);
- startT+=signleLineHeight+lineSpace;
- sb=new StringBuilder();
- ww=0.0f;
- ww+=v;
- sb.append(textChars[i]);
- }
- }
-
- if(sb.toString().length()>0){
- canvas.drawText(sb.toString(),startL,startT,contentPaint);
- }
-
- }
-
- }
自定义属性:
- <declare-styleable name="MyTextView">
- <attr name="paddingLeft" format="dimension" />
- <attr name="paddingTop" format="dimension" />
- <attr name="paddingRight" format="dimension" />
- <attr name="paddingBottom" format="dimension" />
- <attr name="textSize" format="dimension" />
- <attr name="textColor" format="string" />
- <attr name="text" format="string"/>
- <attr name="lineSpacing" format="integer" />
- <attr name="maxLine" format="integer"/>
- <attr name="ellipsis" format="boolean" />
- </declare-styleable>
有的属性的逻辑没添加进去,或者没用上,后面再完善。下面上一个效果图:
view在测量尺寸上可能还是有点问题,用在recyclerview里面,item的布局用的包裹,因为item 的复用关系,该view的尺寸是对的,但是item的尺寸却错乱了,具体原因再找一下。屏蔽方法是:继承recyclerview,重写onMeasure():
- @Override
- protected void onMeasure(int widthSpec, int heightSpec) {
- int customSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
- super.onMeasure(widthSpec, customSpec);
- }
布局上在recyclerview外套一层scrollview,就正常了。后头有空再找找原因。
8.15补充:
上面这个问题,主要是recyclerview复用后,该自定义view的尺寸没有重新绘制,调用一下requestLayout(),重绘一下就对了。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
其他的:
这个问题,好像有个比较好的解决方式,对textview.getText().toString()的字符串,重新测量字符是否够一排,如果够的话就绘制一行,不够的话换行。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。