美文网首页Android
Android 实现一个文字左右不同颜色

Android 实现一个文字左右不同颜色

作者: 水言 | 来源:发表于2017-08-11 17:18 被阅读313次

    偶然看到一个文字用两种颜色显示,这个效果最初是在魅族的应用市场看到的,效果如下:

    效果图1

    第一次看到的时候就觉得很好奇,于是就想着怎么实现,首先从原生控件的角度出发想了想好像没有合适的方法,百度找资料也没找到合适的,于是就想着自己实现下。

    最后实现的效果图:

    效果图2

    文本绘制

    文本绘制这个功能的实现主要是用了系统文本绘制的api:

         canvas.drawText(mText, //文本内容
                    mTextStartX,        //文本绘制开始位置X,Y
                    getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2),
                    mPaint); //画笔
    

    如何使得同一个文本有两种颜色

    实现的原理就是分开两个区域单独用不同的颜色的画笔绘制文本,左边区域绘制颜色A文本,右边区域绘制颜色B文本。
    绘制文本的方法:

     //参数 画布,画笔颜色、开始和结束的X
        private void drawText_h(Canvas canvas, int color, int startX, int endX) {
            mPaint.setColor(color);//画笔颜色
            canvas.save();
            //设置画布的显示区域 ,默认交集显示
            canvas.clipRect(startX, 0, endX, getMeasuredHeight());// left, top,right, bottom
           //正常绘制文本,但是由于画布clip一个固定的范围,实际绘制的文本就在范围中
            canvas.drawText(mText,
                    mTextStartX,
                    //mPaint.descent() + mPaint.ascent()文本高度
                    getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2),
                    mPaint);
            canvas.restore();
        }
    

    ❑ save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。

    ❑ restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。

    执行绘制左右两边文本的代码如下:

     @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
                //左边文本绘制
                drawText_h(canvas,
                            mTextChangeColor,
                            mTextStartX,    //文本开始位置
                            (int) (mTextStartX + mProgress * mTextWidth));  //progress是需要绘制颜色A的范围
                  //右边文本绘制
                    drawText_h(canvas,
                            mTextOriginColor,
                            (int) (mTextStartX + mProgress * mTextWidth),
                            mTextStartX + mTextWidth);
    }
    

    控件大小、文本开始位置控制

    1.首先确定文本区域

        //测量文本内容的宽高
        private void measureText() {
            mTextWidth = (int) mPaint.measureText(mText);
            //文本长度超过屏幕长度,截取前部分,(当然可以换行,实现原理一样过程麻烦点)
            if(mTextWidth>screenWidth){
                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) getLayoutParams();
                int length=(int)(((float)(screenWidth-mlp.bottomMargin-mlp.topMargin)/(float)mTextWidth)*mText.length());
                mText=mText.substring(0,length);
                mTextWidth = (int) mPaint.measureText(mText);
            }
            Paint.FontMetrics fm = mPaint.getFontMetrics();
            mTextHeight = (int) Math.ceil(fm.descent - fm.top);
            mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
            mTextHeight = mTextBound.height();
        }
    

    2.确定控件大小
    控件的测绘模式
    MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为MATCh_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
    MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
    MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。

       //重新计算所需的高度
        private int measureHeight(int measureSpec) {
            int mode = MeasureSpec.getMode(measureSpec); //控件的测绘模式
            int val = MeasureSpec.getSize(measureSpec); //控件大小
            int result = 0;
            switch (mode) {
                case MeasureSpec.EXACTLY:
                    result = val;
                    break;
                case MeasureSpec.AT_MOST:
                case MeasureSpec.UNSPECIFIED:
                //
                    result = mTextHeight;
                    result += getPaddingTop() + getPaddingBottom();
                    break;
            }
            result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
            return result;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            measureText();
            //从新测量控件的大小,确保在没有指定控件大小的情况下正常显示
            int width = measureWidth(widthMeasureSpec);
            int height = measureHeight(heightMeasureSpec);
            setMeasuredDimension(width, height);  
          //确保文本居中显示,获得文本的开始位置
            mTextStartX = getMeasuredWidth() / 2 - mTextWidth / 2;
            mTextStartY = getMeasuredHeight() / 2 - mTextHeight / 2;
        }
    

    自定义控件状态保存

    在横竖屏切换等操作导致Activity重新创建的情况保存数据。

        private static final String PROGRESS = "progress";
        private static final String STATE = "state";
    
        @Override
        protected Parcelable onSaveInstanceState() {
            Bundle bundle = new Bundle();
            bundle.putFloat(PROGRESS, mProgress);
            bundle.putParcelable(STATE, super.onSaveInstanceState());
            return bundle;
        }
    
        @Override
        protected void onRestoreInstanceState(Parcelable state) {
    
            if (state instanceof Bundle) {
                Bundle bundle = (Bundle) state;
                mProgress = bundle.getFloat(PROGRESS);
                super.onRestoreInstanceState(bundle.getParcelable(STATE));
                return;
            }
            super.onRestoreInstanceState(state);
        }
    

    最后附上多颜色文本和下载进度的demo,供参考:
    项目地址:链接:http://pan.baidu.com/s/1geDhtWR 密码:k820

    参考:
    http://blog.csdn.net/lmj623565791/article/details/44098729

    相关文章

      网友评论

        本文标题:Android 实现一个文字左右不同颜色

        本文链接:https://www.haomeiwen.com/subject/mmchrxtx.html