Android custom controls convert font color to create a cool ViewPager indicator and androidviewpager

Source: Internet
Author: User
Tags drawtext getcolor

Android custom controls convert font color to create a cool ViewPager indicator and androidviewpager
Reprinted please indicate the source: bytes

This blog is generated because some friends in the Group sent me a warm email and asked me how to change the font color of the ViewPager indicator on the top. This is the case:


This is probably the toutiao.com app. What's amazing is that when you switch the ViewPager page, the top indicator changes to the font color. I personally think it is good.

So the core is to make a support font so that we can gradually dye it. I thought about 32 s, scanned some possible solutions, and finally located a reliable one, next I will take you on the journey.

Before implementation, paste our:

2. 1. Easy to use


The effect is as shown in the following figure. I have added two directions for the change of face color. One is the left direction and the other is the direction.

Simple use may be meaningless. The following is an example of ViewPager.

2. used in combination with ViewPager


We can see that when we switch the page, the above indicator is very good ~~~

Of course, you have learned the principle, you can expand, you can make a personalized progress bar, you can change the font color to the background color, you can change the direction to the upper and lower, too much, you want to put your feet.

3. Principles

After reading this article, what are the ideas ~~~ It takes a few minutes to think about it, because the principle is very simple ~~

I thought about it, but it is not possible to draw a half-word visually. You can draw all the words in the drawing range, but I control the display range, so the above results:

In fact, the font is drawn twice, but the display range of the painting is controlled separately, and the color changes gradually. So, what convenient API is there for range control, obviously there are

Canvas has a clipRect method ~~~ OK. The principle analysis is complete ~~

4. Implementation

When it comes to implementation, the first step must be a custom attribute. The attributes here need text, textSize, textOriginColor, textChangeColor, and progress. Let's take a look at them and we can see their functions, it cannot be seen that it is okay, combined with the following code. Tip: Our View is called ColorTrackView. Thank you for the name of Xiaoqi.

1. Custom Attributes and Acquisition

Attr. xml

<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="text" format="string" />    <attr name="text_size" format="dimension" />    <attr name="text_origin_color" format="color|reference" />    <attr name="text_change_color" format="color|reference" />    <attr name="progress" format="float" />    <attr name="direction">        <enum name="left" value="0" />        <enum name="right" value="1" />    </attr>    <declare-styleable name="ColorTrackView">        <attr name="text" />        <attr name="text_size" />        <attr name="text_origin_color" />        <attr name="text_change_color" />        <attr name="progress" />        <attr name="direction" />    </declare-styleable></resources>

Then we can obtain these slag attributes in the constructor method of ColorTrackView:

/***** @ Author zhy **/public class ColorTrackView extends View {private int mTextStartX; public enum Direction {LEFT, RIGHT;} private int mDirection = DIRECTION_LEFT; private static final int DIRECTION_LEFT = 0; private static final int DIRECTION_RIGHT = 1; public void setDirection (int direction) {mDirection = direction;} private String mText = "Zhang Hongyang "; private Paint mPaint; private int mTextSize = sp2px (30); private int mTextOriginColor = 0xff000000; private int mTextChangeColor = 0xffff0000; private Rect mTextBound = new Rect (); private int mTextWidth; private int mRealWidth; private float mProgress; public ColorTrackView (Context context) {super (context, null);} public ColorTrackView (Context context, AttributeSet attrs) {super (context, attrs ); mPaint = new Paint (Paint. ANTI_ALIAS_FLAG); TypedArray ta = context. obtainStyledAttributes (attrs, R. styleable. colorTrackView); mText = ta. getString (R. styleable. colorTrackView_text); mTextSize = ta. getDimensionPixelSize (R. styleable. colorTrackView_text_size, mTextSize); mTextOriginColor = ta. getColor (R. styleable. colorTrackView_text_origin_color, mTextOriginColor); mTextChangeColor = ta. getColor (R. styleable. colorTrackView_text_change_color, mTextChangeColor); mProgress = ta. getFloat (R. styleable. colorTrackView_progress, 0); mDirection = ta. getInt (R. styleable. colorTrackView_direction, mDirection); ta. recycle (); mPaint. setTextSize (mTextSize); measureText ();}

private void measureText(){mTextWidth = (int) mPaint.measureText(mText);mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);}

We can see that I have added member variables at the same time. You can simply take a look at them. They are all relatively simple.

After obtaining the attributes and completing initialization of some member variables, we should go to our measure journey ~~

2. onMeasure

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){int width = measureWidth(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);setMeasuredDimension(width, height);mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();mTextStartX = mRealWidth / 2 - mTextWidth / 2;}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 = mTextBound.height();break;}result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;return result + getPaddingTop() + getPaddingBottom();}private int measureWidth(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 = mTextBound.width();result = mTextWidth;break;}result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;return result + getPaddingLeft() + getPaddingRight();}

Measurement is also a traditional method. According to the input widthMeasureSpec and heightMeasureSpec, MeasureSpec is used to obtain the modes and values respectively. How can this problem be solved, if it is AT_MOST or UNSPECIFIED, the space needed for measurement should be carried out. Of course, it is best to note that if it is AT_MOST, it should not be greater than the value passed in by the parent class.

Here, if you are lazy, you can choose to inherit TextView, and then do not need to write the measurement. TextView is implemented by default, and some attributes of TextView can be used, however, this example is relatively simple. In the end, I chose to inherit the View. inheriting the View has the feeling of everything under control.

After the measurement is completed, it should not be said that it is all drawn.

3. onDraw

@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);int r = (int) (mProgress* mTextWidth +mTextStartX );if(mDirection == DIRECTION_LEFT){drawChangeLeft(canvas, r);drawOriginLeft(canvas, r);}else{ drawOriginRight(canvas, r); drawChangeRight(canvas, r);}}private void drawChangeRight(Canvas canvas, int r){drawText(canvas, mTextChangeColor, (int) (mTextStartX +(1-mProgress)*mTextWidth), mTextStartX+mTextWidth );}private void drawOriginRight(Canvas canvas, int r){drawText(canvas, mTextOriginColor, mTextStartX, (int) (mTextStartX +(1-mProgress)*mTextWidth) );}private void drawChangeLeft(Canvas canvas, int r){drawText(canvas, mTextChangeColor, mTextStartX, (int) (mTextStartX + mProgress * mTextWidth) );}private void drawOriginLeft(Canvas canvas, int r){drawText(canvas, mTextOriginColor, (int) (mTextStartX + mProgress * mTextWidth), mTextStartX +mTextWidth );}private void drawText(Canvas canvas , int color , int startX , int endX){mPaint.setColor(color);canvas.save(Canvas.CLIP_SAVE_FLAG);canvas.clipRect(startX, 0, endX, getMeasuredHeight());canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2+ mTextBound.height() / 2, mPaint);canvas.restore();}

The core of drawing is to use mProgress and direction to calculate the range of clip. For specific reference code, there is no difficulty. When the range is available, it is nothing more than drawText ~~~

Complete code for this View: ColorTrackView

After introducing the main method, we should test it.

5. Test
1. Simple Test

Layout File

<RelativeLayout xmlns: android = "http://schemas.android.com/apk/res/android" xmlns: tools = "http://schemas.android.com/tools" xmlns: zhy = "http://schemas.android.com/apk/res-auto" android: layout_width = "match_parent" android: layout_height = "match_parent"> <com. zhy. view. colorTrackView android: id = "@ + id/id_changeTextColorView" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_centerInParent = "true" android: background = "#44ff0000" android: padding = "10dp" zhy: progress = "0" zhy: text = "Zhang Hongyang" zhy: text_change_color = "# ffff0000" zhy: text_origin_color = "# ff000000" zhy: text_size = "60sp"/> <LinearLayout android: layout_width = "match_parent" android: layout_height = "wrap_content" android: true = "android: gravity = "center" android: orientation = "horizontal"> <Button android: id = "@ + id/id_left" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: onClick = "startLeftChange" android: text = "StartLeft"/> <Button android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toRightOf = "@ id/id_left" android: onClick = "startRightChange" android: text = "StartRight"/> </LinearLayout> </RelativeLayout>

Pay attention to the namespace of our custom properties. The layout is a ColorTrackView, and then two buttons are used to control the progress.

SimpleUseActivity:

package com.zhy.viewpagerIndicator;import android.animation.ObjectAnimator;import android.annotation.SuppressLint;import android.app.Activity;import android.os.Bundle;import android.view.View;import com.zhy.view.ColorTrackView;public class SimpleUseActivity extends Activity{ColorTrackView mView;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_simple_main);mView = (ColorTrackView) findViewById(R.id.id_changeTextColorView);}@SuppressLint("NewApi")public void startLeftChange(View view){mView.setDirection(0);ObjectAnimator.ofFloat(mView, "progress", 0, 1).setDuration(2000).start();}@SuppressLint("NewApi")public void startRightChange(View view){mView.setDirection(1);ObjectAnimator.ofFloat(mView, "progress", 0, 1).setDuration(2000).start();}}

The property animation test is carried out here. The compatibility package below 3.0 is not imported. You need to import the package yourself.

, See 1.

2. Combined with ViewPager

Layout file:

<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android" xmlns: zhy = "http://schemas.android.com/apk/res-auto" xmlns: tools = "http://schemas.android.com/tools" android: layout_width = "match_parent" android: layout_height = "match_parent" android: orientation = "vertical"> <LinearLayout android: layout_width = "match_parent" android: layout_height = "50dp" android: orientation = "horizontal"> <com. zhy. view. colorTrackView android: id = "@ + id/id_tab_01" android: layout_width = "0dp" android: layout_height = "match_parent" android: layout_weight = "1" zhy: progress = "1" zhy: text = "" zhy: text_change_color = "# ffff0000" zhy: text_origin_color = "# ff000000" zhy: text_size = "18sp"/> <com. zhy. view. colorTrackView android: id = "@ + id/id_tab_02" android: layout_width = "0dp" android: layout_height = "match_parent" android: layout_weight = "1" zhy: text = "comment" zhy: text_change_color = "# ffff0000" zhy: text_origin_color = "# ff000000" zhy: text_size = "18sp"/> <com. zhy. view. colorTrackView android: id = "@ + id/id_tab_03" android: layout_width = "0dp" android: layout_height = "match_parent" android: layout_weight = "1" zhy: text = "related" zhy: text_change_color = "# ffff0000" zhy: text_origin_color = "# ff000000" zhy: text_size = "18sp"/> </LinearLayout> <android. support. v4.view. viewPager android: id = "@ + id/id_viewpager" android: layout_width = "match_parent" android: layout_height = "0dp" android: layout_weight = "1"> </android. support. v4.view. viewPager> </LinearLayout>

Three colortrackviews represent tabs. The following is ViewPager.

ViewPagerUseActivity:

Package com. zhy. viewpagerIndicator; import java. util. arrayList; import java. util. list; import android. OS. bundle; import android. support. v4.app. fragment; import android. support. v4.app. fragmentActivity; import android. support. v4.app. fragmentPagerAdapter; import android. support. v4.view. viewPager; import android. support. v4.view. viewPager. onPageChangeListener; import android. util. log; import com. zhy. view. colorTrackView; public class ViewPagerUseActivity extends FragmentActivity {private String [] mTitles = new String [] {"Introduction", "comment", "related"}; private ViewPager mViewPager; private FragmentPagerAdapter mAdapter; private TabFragment [] mFragments = new TabFragment [mTitles. length]; private List <ColorTrackView> mTabs = new ArrayList <ColorTrackView> (); @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_vp_main); initViews (); initDatas (); initEvents ();} private void initEvents () {mViewPager. listener (new OnPageChangeListener () {@ Overridepublic void onPageSelected (int position) {}@ Overridepublic void evaluate (int position, float positionOffset, int positionOffsetPixels) {if (positionOffset> 0) {ColorTrackView left = mTabs. get (position); ColorTrackView right = mTabs. get (position + 1); left. setDirection (1); right. setDirection (0); Log. e ("TAG", positionOffset + ""); left. setProgress (1-positionOffset); right. setProgress (positionOffset) ;}}@ Overridepublic void onPageScrollStateChanged (int state) {}});} private void initDatas () {for (int I = 0; I <mTitles. length; I ++) {mFragments [I] = (TabFragment) TabFragment. newInstance (mTitles [I]);} mAdapter = new FragmentPagerAdapter (getSupportFragmentManager () {@ Overridepublic int getCount () {return mTitles. length ;}@ Overridepublic Fragment getItem (int position) {return mFragments [position] ;}; mViewPager. setAdapter (mAdapter); mViewPager. setCurrentItem (0);} private void initViews () {mViewPager = (ViewPager) findViewById (R. id. id_viewpager); mTabs. add (ColorTrackView) findViewById (R. id. id_tab_01); mTabs. add (ColorTrackView) findViewById (R. id. id_tab_02); mTabs. add (ColorTrackView) findViewById (R. id. id_tab_03 ));}}

TabFragment

package com.zhy.viewpagerIndicator;import java.util.Random;import android.graphics.Color;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;public class TabFragment extends Fragment{public static final String TITLE = "title";private String mTitle = "Defaut Value";@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);if (getArguments() != null){mTitle = getArguments().getString(TITLE);}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){TextView tv = new TextView(getActivity());tv.setTextSize(60);Random r = new Random();tv.setBackgroundColor(Color.argb(r.nextInt(120), r.nextInt(255),r.nextInt(255), r.nextInt(255)));tv.setText(mTitle);tv.setGravity(Gravity.CENTER);return tv;}public static TabFragment newInstance(String title){TabFragment tabFragment = new TabFragment();Bundle bundle = new Bundle();bundle.putString(TITLE, title);tabFragment.setArguments(bundle);return tabFragment;}}

See figure 2.


Source Code address: ColorTrackView. Welcome to star or fork.

Group Number:429757068

Scan the Public Account (notify blogs, videos, and other notifications as soon as possible ):














Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.