美文网首页Android自定义View安卓开发博客
自定义View(4) -- 字体变色

自定义View(4) -- 字体变色

作者: 曾大稳丶 | 来源:发表于2017-06-16 10:54 被阅读0次
    字体变色.gif

    初始化我就不说了,先思考我们需要什么属性,这里我就随便写了两个,一个是变色的颜色,一个是正常的颜色,当然也可以是默认的字体颜色,我们在attr里面申明

     <declare-styleable name="ColorTrackTextView">
            <attr name="originColor" format="color" />
            <attr name="changeColor" format="color" />
        </declare-styleable>
    
       private int mOriginColor;//不变化的颜色
        private int mChangeColor;//变化的颜色
        private Paint mOriginPaint, mChangePaint;
    
      private void init(Context context, AttributeSet attrs) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
            mOriginColor = ta.getColor(R.styleable.ColorTrackTextView_originColor, Color.BLACK);
            mChangeColor = ta.getColor(R.styleable.ColorTrackTextView_changeColor, Color.RED);
            ta.recycle();
    
            mOriginPaint = new Paint();
            mOriginPaint.setColor(mOriginColor);
            mOriginPaint.setAntiAlias(true);
            mOriginPaint.setTextSize(getTextSize());
    
            mChangePaint = new Paint();
            mChangePaint.setColor(mChangeColor);
            mChangePaint.setAntiAlias(true);
            mChangePaint.setTextSize(getTextSize());
    
        }
    

    因为我们选择了继承的是TextView,所以我们就不进行 onMeasure(),我们重写onDraw(),覆盖原有的绘制逻辑,我们自己来绘制,这里我们主要使用canvas.clipRect(rect)这个函数来实现裁剪,我们先来测试:

    //思路:利用clipRect  来裁剪   使用两个画笔
        @Override
        protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);   //不使用TextView的绘制 自己画
    
            canvas.save();
            int mid = 500;
            Rect rect = new Rect(0, 0, mid, getHeight());
            canvas.clipRect(rect);
    
            String text = getText().toString();
            int x = (int) (getPaddingLeft() + getWidth() / 2 - mOriginPaint.measureText(text) / 2);
            int y = getPaddingTop() + DisplayUtil.getTextBaseLine(getHeight(), mOriginPaint);
            canvas.drawText(text, x, y, mChangePaint);
            canvas.restore();
    
            canvas.save();
            rect.set(mid, 0, getWidth(), getHeight());
            canvas.clipRect(rect);
            canvas.drawText(text, x, y, mOriginPaint);
            canvas.restore();
        }
    
     <com.zzw.customview.view.ColorTrackTextView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/colortv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            android:gravity="center"
            android:text="1111111"
            android:textSize="50sp"
            app:changeColor="@color/colorAccent"
            app:originColor="@color/colorPrimary" />
    

    可以看到,我们是有效果的,因为我们考略到要和 ViewPager 一起配合使用,所以我们定义一个float类型的mCurrentProgress属性,用于表示当前的滑动进度,在设置一个方向,颜色是从左到右变化还是从右到左的变化

      //不同的朝向
        public static final int DIRECTION_LEFT_TO_RIGHT = 1;//从左边变色
        public static final int DIRECTION_RIGHT_TO_LEFT = 2;//从右边变色
    
    
        private int mDirection = DIRECTION_LEFT_TO_RIGHT;
    
        //当前进度
        private float mCurrentProgress;
    
    

    接下来我们修改onDraw()以及优化一下赘余代码:

     //思路:利用clipRect  来裁剪   使用两个画笔
        @Override
        protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);   //不使用TextView的绘制 自己画
    
            int mid = comMiddle();
            if (mDirection == DIRECTION_LEFT_TO_RIGHT) {
                drawText(canvas, mChangePaint, 0, mid); //画左边  颜色
                drawText(canvas, mOriginPaint, mid, getWidth());//画右边
            } else {
                mid = getWidth() - mid;
                drawText(canvas, mChangePaint, mid, getWidth());//画右边  颜色
                drawText(canvas, mOriginPaint, 0, mid); //画左边
            }
        }
    
        /**
         * 根据当前进度算出中间值
         *
         * @return
         */
        private int comMiddle() {
            return (int) (mCurrentProgress * getWidth());
        }
    
    
        /**
         * 根据start  end  确定rect绘制文字
         *
         * @param canvas
         * @param paint
         * @param start
         * @param end
         */
        private void drawText(Canvas canvas, Paint paint, int start, int end) {
            canvas.save();
            Rect rect = new Rect(start, 0, end, getHeight());//确定区域
            canvas.clipRect(rect);
    
            String text = getText().toString();
            int x = (int) (getPaddingLeft() + getWidth() / 2 - paint.measureText(text) / 2);
            int y = getPaddingTop() + DisplayUtil.getTextBaseLine(getHeight(), paint);
            canvas.drawText(text, x, y, paint);
            canvas.restore();
        }
    
    

    接下来我们进行测试

     public void leftToRight(View view) {
            mColorTrackTextView.setDirection(ColorTrackTextView.DIRECTION_LEFT_TO_RIGHT);
            startAnim(0, 1);
        }
    
        public void RightToLeft(View view) {
            mColorTrackTextView.setDirection(ColorTrackTextView.DIRECTION_RIGHT_TO_LEFT);
            startAnim(0, 1);
        }
    
    
        private void startAnim(float startPro, float endPro) {
            ValueAnimator animator = ObjectAnimator.ofFloat(startPro, endPro);
            animator.setDuration(2000);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float currentProgress = (float) animation.getAnimatedValue();
                    mColorTrackTextView.setCurrentProgress(currentProgress);
                }
            });
            animator.start();
        }
    
    

    就会得到如下图的效果:


    字体变色测试.gif

    感觉离成功近了一步,这里我们顺便优化了一个性能的问题,因为是不端的调用setCurrentProgress()方法进行重新绘制,所以这里我们加个判断:

    public void setCurrentProgress(float currentProgress) {
            if (mCurrentProgress == currentProgress)//当前进度相同就不执行下一步
                return;
    
            this.mCurrentProgress = currentProgress;
            invalidate();
        }
    

    让它重复的时候不进行重绘,这只是一个小细节,接下来我们和ViewPager配合使用。我们在开发中一般遇到的是根据一个数据源,然后动态的添加FragmentViewPager进行关联,这里我们模拟这个场景。我们使用一个LinearLayout来管理这些字体变色的viewViewPagerOnPageChangeListener来管理字体变色,布局为下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:paddingTop="10dp"
            android:paddingBottom="10dp"
            android:id="@+id/indicator_view"
            android:layout_height="wrap_content"/>
    
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:id="@+id/view_pager"
            android:layout_weight="1"
            />
    </LinearLayout>
    

    然后我们在代码中动态的添加:

    package com.zzw.customview;
    
    import android.graphics.Color;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    
    import com.zzw.customview.view.ColorTrackTextView;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by zzw on 2017/6/15.
     * Version:
     * Des: 字体变色和viewpager配合使用
     */
    public class ViewPagerActivity extends AppCompatActivity {
        private String[] items = {"热点", "推荐", "社会", "图片", "科技", "运动"};
        private LinearLayout mIndicatorContainer;// 变成通用的
        private List<ColorTrackTextView> mIndicators;
        private ViewPager mViewPager;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_view_pager);
    
            mIndicators = new ArrayList<>();
            mIndicatorContainer = (LinearLayout) findViewById(R.id.indicator_view);
            mViewPager = (ViewPager) findViewById(R.id.view_pager);
            initIndicator();
            initViewPager();
        }
    
        /**
         * 初始化ViewPager
         */
        private void initViewPager() {
            mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
                @Override
                public Fragment getItem(int position) {
                    return ItemFragment.newInstance(items[position]);
                }
    
                @Override
                public int getCount() {
                    return items.length;
                }
    
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
    
                }
            });
    
            mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    Log.e("TAG", "position -> " + position + "  positionOffset -> " + positionOffset + "  positionOffsetPixels->" + positionOffsetPixels);
                    // position 代表当前的位置
                    // positionOffset 代表滚动的 0 - 1 百分比  左滑 1->0  右滑-> 0-1
    
                    // 1.左边  位置 position
                    ColorTrackTextView left = mIndicators.get(position);
                    left.setDirection(ColorTrackTextView.DIRECTION_RIGHT_TO_LEFT);
                    left.setCurrentProgress(1 - positionOffset);
    
                    try {
                        ColorTrackTextView right = mIndicators.get(position + 1);
                        right.setDirection(ColorTrackTextView.DIRECTION_LEFT_TO_RIGHT);
                        right.setCurrentProgress(positionOffset);
                    } catch (Exception e) {
    
                    }
                }
    
                @Override
                public void onPageSelected(int position) {
                    
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {
    
                }
            });
        }
    
        /**
         * 初始化可变色的指示器
         */
        private void initIndicator() {
            for (int i = 0; i < items.length; i++) {
                // 动态添加颜色跟踪的TextView
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
               ViewGroup.LayoutParams.WRAP_CONTENT);
                params.weight = 1;
                ColorTrackTextView colorTrackTextView = new ColorTrackTextView(this);
                // 设置颜色
                colorTrackTextView.setTextSize(20);
                colorTrackTextView.setChangeColor(Color.RED);
                colorTrackTextView.setText(items[i]);
                colorTrackTextView.setLayoutParams(params);
    
                // 把新的加入LinearLayout容器
                mIndicatorContainer.addView(colorTrackTextView);
                // 加入集合
                mIndicators.add(colorTrackTextView);
            }
        }
    

    这里我们发现左右滑动的时候可以实现了,但是点击tab的时候还会出现上一个没有变色的情况,这里我就不上图了,我们直接写一个函数,在选中之后把重新设置颜色即可。

      private void selectPos(int pos) {
            for (int i = 0; i < mIndicators.size(); i++) {
                ColorTrackTextView colorTrackTextView = mIndicators.get(i);
                if (i == pos) {
                    colorTrackTextView.setCurrentProgress(1.0f);
                } else {
                    colorTrackTextView.setCurrentProgress(0.0f);
                }
            }
        }
    

    最后要说的是,优化问题,在这篇文章中我们在绘制的过程中就已经进行优化了,我们要养成这种好习惯,不管是代码上还是性能上。
    下载地址:https://github.com/ChinaZeng/CustomView

    参考链接:http://www.jianshu.com/p/6e4b3eebbba0

    相关文章

      网友评论

        本文标题:自定义View(4) -- 字体变色

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