Android_字体变色,viewpager指示器

简介

本篇是来自鸿洋_大神的Android 自定义控件玩转字体变色 打造炫酷ViewPager指示器这篇博客,刚开始看时觉得不是很好理解,现在自己减去了他的一些代码,自己写的一个,也实现了同样的效果,感觉好理解多了。
先看一下实现后的效果:
技术分享

要实现这样的文字跟随viewpager的滑动而逐渐改变颜色的效果,这里很明显底色字一直在的,所以我们要考虑的主要是红色字体的绘制。绘制红色字体用的是canvas的clipRect()方法。根据要改变的宽度系数,切割要绘制的位置。这里运用了自定义属性,方便我们修改一些控件的属性。

1,自定义属性

attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="text" format="string"/>
    <attr name="textSize" format="dimension"/>
    <attr name="textOriginColor" format="color"/>
    <attr name="textChangeColor" format="color"/>
    <attr name="progress" format="float"/>
    <attr name="direction" >
        <enum name="left" value="0" />  
        <enum name="right" value="1" />  
    </attr>

    <declare-styleable name = "colortractview">
         <attr name="text" />  
        <attr name="textSize" />  
        <attr name="textOriginColor" />  
        <attr name="textChangeColor" />  
        <attr name="progress" />  
        <attr name="direction" />  
    </declare-styleable>
</resources>

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:raise="http://schemas.android.com/apk/res/com.raise.colortrackview"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff" >

    <com.raise.colortrackview.ColorTrackView
        android:id="@+id/colortractview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#ddd"
        raise:text="ColorTract测试"
        raise:textChangeColor="#ff0000"
        raise:textSize="30sp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal" >

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="left" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="rihgt" />
    </LinearLayout>

</FrameLayout>

ColorTrackView.java源码

package com.raise.colortrackview;

import com.raise.colortrackview.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class ColorTrackView extends View {

    //一些默认值
    private static final int DEFAULT_TEXTSIZE = 20;
    private static final int DIRECTION_LEFT = 0;
    private static final int DIRECTION_RIGHT = 1;
    private static final int DEFAULT_ORIGHT_COLOR = Color.BLACK;
    private static final int DEFAULT_CHANGE_COLOR = Color.RED;
/**
 * 设置颜色变化方向值
 * @author raise
 *
 */
    public enum Direction{
        Left,Right
    }
    /**
     * 字体画笔
     */
    private Paint mPaint;
    /**
     * 要画出的文字
     */
    private String mText;
    /**
     * 文字大小
     */
    private int mTextSize;
    /**
     * 原文字颜色
     */
    private int mOriginColor;
    /**
     * 拖动后的文字颜色
     */
    private int mChangeColor;
    /**
     * 变化进度
     */
    private float mProgress;
    /**
     * 变化方向
     */
    private int mDirection;
    /**
     * view的宽
     */
    private int mWidth;
    /**
     * view的高
     */
    private int mHeight;

    public ColorTrackView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mPaint = new Paint();
        //读取自定义属性
        initDatas(context, attrs);
        //设置默认标题
        mText = mText == null ? "标题" : mText;
        mPaint.setTextSize(mTextSize);
        //字体的宽度和高度,作为该控件的宽度和高度
        mWidth = (int) mPaint.measureText(mText);
        mHeight = (int) (mPaint.descent() - mPaint.ascent());

//      setBackgroundColor(Color.parseColor("#f1f1f1"));
    }

    private void initDatas(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.colortractview);
        mText = ta.getString(R.styleable.colortractview_text);
        mTextSize = ta.getDimensionPixelOffset(
                R.styleable.colortractview_textSize, sp2px(DEFAULT_TEXTSIZE));
        mDirection = ta.getInt(R.styleable.colortractview_direction,
                DIRECTION_LEFT);
        mOriginColor = ta.getColor(R.styleable.colortractview_textOriginColor,
                DEFAULT_ORIGHT_COLOR);
        mChangeColor = ta.getColor(R.styleable.colortractview_textChangeColor,
                DEFAULT_CHANGE_COLOR);
        mProgress = ta.getFloat(R.styleable.colortractview_progress, 0f);
        ta.recycle();
    }

    public ColorTrackView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ColorTrackView(Context context) {
        this(context, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // view的width,height等于字体的
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth,
                MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mHeight,
                MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int startX = (int) (mProgress * mWidth);
        // 第一次绘出原字体
        mPaint.setColor(mOriginColor);
        canvas.drawText(mText, 0, mHeight - mPaint.descent(), mPaint);
        mPaint.setColor(mChangeColor);
        canvas.save();
        //第二次绘出变色字体
        if (mDirection == DIRECTION_LEFT) {
            //变色字出现在左边,起点当然是(0,0)
            canvas.clipRect(0, 0, startX, mHeight);
        } else if (mDirection == DIRECTION_RIGHT) {
            //变色字出现在右边,终点当然是(mWidth,mHeight)
            canvas.clipRect(mWidth-startX, 0, mWidth, mHeight);
        }
        //在指定区域绘出变色字
        canvas.drawText(mText, 0, mHeight - mPaint.descent(), mPaint);
        canvas.restore();
    }

    private int dp2px(int value) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                value, getResources().getDisplayMetrics());
    }

    private int sp2px(int value) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                value, getResources().getDisplayMetrics());
    }
    public int getmDirection() {
        return mDirection;
    }

    public void setDirection(int direction) {
        this.mDirection = direction;
    }

    public void setProgress(float progress) {
        this.mProgress = progress;
        //注意这里要重绘
        invalidate();
    }

}

和大神区别在于,我使用了字体的大小,做为该View的大小,这样理解起来简单了许多,在使用的时候,只要在外部多加一层Linearlayout就可以了。
MainActivity.java源码:

public class MainActivity extends Activity implements OnClickListener {

    ColorTrackView view ;
    Button leftbButton;
    Button rightButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view = (ColorTrackView) findViewById(R.id.colortractview);
        leftbButton = (Button) findViewById(R.id.button1);
        rightButton = (Button) findViewById(R.id.button2);

        leftbButton.setOnClickListener(this);
        rightButton.setOnClickListener(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onClick(View v) {
        if (v == leftbButton) {
            view.setDirection(0);
            Toast.makeText(MainActivity.this, "left", 1).show();
            ObjectAnimator.ofFloat(view, "progress", 0f,1f).setDuration(2000).start();
        }else if (v == rightButton) {
            Toast.makeText(MainActivity.this, "right", 1).show();
            view.setDirection(1);
            ObjectAnimator.ofFloat(view, "progress", 0f,1f).setDuration(2000).start();

        }

    }

}

效果图:
技术分享
和预想的一样,看来简化后没问题。
下面看下将其使用到viewpager上。
TabFragment.java

public class TabFragment extends Fragment {

    private static final String TITLE = "title";

    private String mTitle = "default title";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        Bundle bundle = getArguments();
        if (bundle!=null) {
            mTitle = bundle.getString(TITLE);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        TextView view = new TextView(getActivity());
        view.setTextSize(30);
        Random r = new Random();
        view.setBackgroundColor(Color.argb(r.nextInt(120), r.nextInt(255),
                r.nextInt(255), r.nextInt(255)));
        view.setGravity(Gravity.CENTER);
        view.setText(mTitle);
        return view;
    }

    public static Fragment newInstance(String title) {
        TabFragment fragment = new TabFragment();
        Bundle bundle = new Bundle();
        bundle.putString(TITLE, title);
        fragment.setArguments(bundle);
        return fragment;

    }

}

TestActivity.java

public class TestActivity extends FragmentActivity implements
        OnPageChangeListener {

    private String[] mTitles = { "生活", "科技", "体育" };
    private ViewPager viewPager;
    //装载指示器的list
    private List<ColorTrackView> viewList = new ArrayList<ColorTrackView>();
    private ColorTrackView colorView1;
    private ColorTrackView colorView2;
    private ColorTrackView colorView3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        initView();
        viewPager.setAdapter(adapter);
        viewPager.setOnPageChangeListener(this);
        viewList.add(colorView1);
        viewList.add(colorView2);
        viewList.add(colorView3);

        viewList.get(0).setProgress(1);
    }

    private void initView() {
        viewPager = (ViewPager) findViewById(R.id.viewpage);
        colorView1 = (ColorTrackView) findViewById(R.id.view_color1);
        colorView2 = (ColorTrackView) findViewById(R.id.view_color2);
        colorView3 = (ColorTrackView) findViewById(R.id.view_color3);
    }

    FragmentPagerAdapter adapter = new FragmentPagerAdapter(
            getSupportFragmentManager()) {
        @Override
        public int getCount() {
            return mTitles.length;
        }
        @Override
        public Fragment getItem(int arg0) {
            return TabFragment.newInstance(mTitles[arg0]);
        }
    };

    @Override
    public void onPageScrollStateChanged(int arg0) {
    }
    /*
     * arg0是左边的fragment坐标,arg1,0-1滑动系数,arg2隐藏的宽度
     */
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        // 不可滑动时退出
        if (arg1 == 0f) {
            return;
        }
        // 得到左边的view
        ColorTrackView leftView = viewList.get(arg0);
        // 得到右边的view
        ColorTrackView rightView = viewList.get(arg0 + 1);
        // 设置左边view指示器状态
        leftView.setDirection(1);
        leftView.setProgress(1 - arg1);
        // 设置右边view指示器状态
        rightView.setDirection(0);
        rightView.setProgress(arg1);
    }

    @Override
    public void onPageSelected(int arg0) {
    }
}

activity_test.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:raise="http://schemas.android.com/apk/res/com.raise.colortrackview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="#f1f1f1"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:weightSum="3" >

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.raise.colortrackview.ColorTrackView
                android:id="@+id/view_color1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                raise:text="生活"
                raise:textChangeColor="#c96666" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.raise.colortrackview.ColorTrackView
                android:id="@+id/view_color2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                raise:text="科技"
                raise:textChangeColor="#c96666" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.raise.colortrackview.ColorTrackView
                android:id="@+id/view_color3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                raise:text="体育"
                raise:textChangeColor="#c96666" />
        </LinearLayout>
    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpage"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

源码:点我下载

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。