Android 高仿微信6.0主界面 带你玩转切换图标变色

时间:2022-09-04 23:37:08
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41087219,本文出自:【张鸿洋的博客】

1、概述

学习Android少不了模仿各种app的界面,自从微信6.0问世以后,就觉得微信切换时那个变色的Tab图标屌屌的,今天我就带大家自定义控件,带你变色变得飞起~~

好了,下面先看下效果图:

Android 高仿微信6.0主界面 带你玩转切换图标变色

清晰度不太好,大家凑合看~~有木有觉得这个颜色弱爆了了的,,,下面我动动手指给你换个颜色:

Android 高仿微信6.0主界面 带你玩转切换图标变色

有没有这个颜色比较妖一点~~~好了~下面开始介绍原理。

2、原理介绍

通过上面的效果图,大家可能也猜到了,我们的图标并非是两张图片,而是一张图,并且目标颜色是可定制的,谁让现在动不动就谈个性化呢。

那么我们如何做到,可以让图标随心所遇的变色了,其实原理,在我的博客中出现了很多次了,下面你将看到一张熟悉的图:

Android 高仿微信6.0主界面 带你玩转切换图标变色

有没有很熟悉的感脚,我们实际上还是利用了Paint的Xfermode,这次我们使用的是:Mode.DST_IN

Dst_IN回顾一下什么效果,先绘制Dst,设置Mode,再绘制Src,则显示的是先后绘图的交集区域,且是Dst.

再仔细观察下我们的图标:

Android 高仿微信6.0主界面 带你玩转切换图标变色

为了方便大家的观看,我特意拿ps选择了一下我们图标的非透明区域,可以看到,我们这个小机器人非透明区域就是被线框起来的部分。

然后,我们图标变色的原理就出现了:

1、先绘制一个颜色(例如:粉红)

2、设置Mode=DST_IN

3、绘制我们这个可爱的小机器人

回答我,显示什么,是不是显示交集,交集是什么?交集是我们的小机器人的非透明区域,也就是那张脸,除了两个眼;

好了,那怎么变色呢?

我绘制一个颜色的时候,难道不能设置alpha么~~~

到此,大家应该已经了解了我们图标的绘制的原理了吧。

如果你对Mode不熟悉:建议移步至:Android 自定义控件实现刮刮卡效果 真的就只是刮刮卡么


3、自定义图标控件

我们的整个界面不用说,是ViewPager+Fragment ,现在关注的是底部~~

接下来我们考虑,底部的Tab,Tab我们的布局是LinearLayout,内部四个View,通过设置weight达到均分~~

这个View就是我们的自定义的图标控件了,我们叫做:ChangeColorIconWithTextView

接下来考虑,应该有什么属性公布出来

1、自定义属性

想了一下,我决定把图标,图标颜色,图标下显示的文字,文字大小这四个属性作为自定义属性。

那就自定义属性走起了:

a、values/attr.xml

[java] view plain copy print?
  1. <?xml version=“1.0” encoding=“utf-8”?>  
  2. <resources>  
  3.   
  4.     <attr name=”icon” format=“reference” />  
  5.     <attr name=”color” format=“color” />  
  6.     <attr name=”text” format=“string” />  
  7.     <attr name=”text_size” format=“dimension” />  
  8.   
  9.     <declare-styleable name=”ChangeColorIconView”>  
  10.         <attr name=”icon” />  
  11.         <attr name=”color” />  
  12.         <attr name=”text” />  
  13.         <attr name=”text_size” />  
  14.     </declare-styleable>  
  15.   
  16. </resources>  
<?xml version="1.0" encoding="utf-8"?><resources>

<attr name="icon" format="reference" />
<attr name="color" format="color" />
<attr name="text" format="string" />
<attr name="text_size" format="dimension" />

<declare-styleable name="ChangeColorIconView">
<attr name="icon" />
<attr name="color" />
<attr name="text" />
<attr name="text_size" />
</declare-styleable>

</resources>

b、在布局文件中使用

[html] view plain copy print?
  1. <com.zhy.weixin6.ui.ChangeColorIconWithTextView  
  2.            android:id=“@+id/id_indicator_one”  
  3.            android:layout_width=“0dp”  
  4.            android:layout_height=“fill_parent”  
  5.            android:layout_weight=“1”  
  6.            android:padding=“5dp”  
  7.            zhy:icon=“@drawable/ic_menu_start_conversation”  
  8.            zhy:text=“@string/tab_weixin”  
  9.            zhy:text_size=“12sp” />  
 <com.zhy.weixin6.ui.ChangeColorIconWithTextView            android:id="@+id/id_indicator_one"            android:layout_width="0dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:padding="5dp"            zhy:icon="@drawable/ic_menu_start_conversation"            zhy:text="@string/tab_weixin"            zhy:text_size="12sp" />

自己注意命名空间的写法,xmlns:zhy=”http://schemas.android.com/apk/res/应用的包名”。

c、在构造方法中获取

[java] view plain copy print?
  1. public class ChangeColorIconWithTextView extends View  
  2. {  
  3.   
  4.     private Bitmap mBitmap;  
  5.     private Canvas mCanvas;  
  6.     private Paint mPaint;  
  7.     /** 
  8.      * 颜色 
  9.      */  
  10.     private int mColor = 0xFF45C01A;  
  11.     /** 
  12.      * 透明度 0.0-1.0 
  13.      */  
  14.     private float mAlpha = 0f;  
  15.     /** 
  16.      * 图标 
  17.      */  
  18.     private Bitmap mIconBitmap;  
  19.     /** 
  20.      * 限制绘制icon的范围 
  21.      */  
  22.     private Rect mIconRect;  
  23.     /** 
  24.      * icon底部文本 
  25.      */  
  26.     private String mText = “微信”;  
  27.     private int mTextSize = (int) TypedValue.applyDimension(  
  28.             TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics());  
  29.     private Paint mTextPaint;  
  30.     private Rect mTextBound = new Rect();  
  31.   
  32.     public ChangeColorIconWithTextView(Context context)  
  33.     {  
  34.         super(context);  
  35.     }  
  36.   
  37.     /** 
  38.      * 初始化自定义属性值 
  39.      *  
  40.      * @param context 
  41.      * @param attrs 
  42.      */  
  43.     public ChangeColorIconWithTextView(Context context, AttributeSet attrs)  
  44.     {  
  45.         super(context, attrs);  
  46.   
  47.         // 获取设置的图标  
  48.         TypedArray a = context.obtainStyledAttributes(attrs,  
  49.                 R.styleable.ChangeColorIconView);  
  50.   
  51.         int n = a.getIndexCount();  
  52.         for (int i = 0; i < n; i++)  
  53.         {  
  54.   
  55.             int attr = a.getIndex(i);  
  56.             switch (attr)  
  57.             {  
  58.             case R.styleable.ChangeColorIconView_icon:  
  59.                 BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);  
  60.                 mIconBitmap = drawable.getBitmap();  
  61.                 break;  
  62.             case R.styleable.ChangeColorIconView_color:  
  63.                 mColor = a.getColor(attr, 0x45C01A);  
  64.                 break;  
  65.             case R.styleable.ChangeColorIconView_text:  
  66.                 mText = a.getString(attr);  
  67.                 break;  
  68.             case R.styleable.ChangeColorIconView_text_size:  
  69.                 mTextSize = (int) a.getDimension(attr, TypedValue  
  70.                         .applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,  
  71.                                 getResources().getDisplayMetrics()));  
  72.                 break;  
  73.   
  74.             }  
  75.         }  
  76.   
  77.         a.recycle();  
  78.   
  79.         mTextPaint = new Paint();  
  80.         mTextPaint.setTextSize(mTextSize);  
  81.         mTextPaint.setColor(0xff555555);  
  82.         // 得到text绘制范围  
  83.         mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);  
  84.   
  85.     }  
public class ChangeColorIconWithTextView extends View{    private Bitmap mBitmap;    private Canvas mCanvas;    private Paint mPaint;    /**     * 颜色     */    private int mColor = 0xFF45C01A;    /**     * 透明度 0.0-1.0     */    private float mAlpha = 0f;    /**     * 图标     */    private Bitmap mIconBitmap;    /**     * 限制绘制icon的范围     */    private Rect mIconRect;    /**     * icon底部文本     */    private String mText = "微信";    private int mTextSize = (int) TypedValue.applyDimension(            TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics());    private Paint mTextPaint;    private Rect mTextBound = new Rect();    public ChangeColorIconWithTextView(Context context)    {        super(context);    }    /**     * 初始化自定义属性值     *      * @param context     * @param attrs     */    public ChangeColorIconWithTextView(Context context, AttributeSet attrs)    {        super(context, attrs);        // 获取设置的图标        TypedArray a = context.obtainStyledAttributes(attrs,                R.styleable.ChangeColorIconView);        int n = a.getIndexCount();        for (int i = 0; i < n; i++)        {            int attr = a.getIndex(i);            switch (attr)            {            case R.styleable.ChangeColorIconView_icon:                BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);                mIconBitmap = drawable.getBitmap();                break;            case R.styleable.ChangeColorIconView_color:                mColor = a.getColor(attr, 0x45C01A);                break;            case R.styleable.ChangeColorIconView_text:                mText = a.getString(attr);                break;            case R.styleable.ChangeColorIconView_text_size:                mTextSize = (int) a.getDimension(attr, TypedValue                        .applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,                                getResources().getDisplayMetrics()));                break;            }        }        a.recycle();        mTextPaint = new Paint();        mTextPaint.setTextSize(mTextSize);        mTextPaint.setColor(0xff555555);        // 得到text绘制范围        mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);    }

可以看到,我们在构造方法中获取了自定义的属性,并且计算了文本占据的控件存在我们的mTextBound中。

2、图标的绘制区域的选择

我们考虑下,有了属性,我们需要绘制一个文本,文本之上一个图标,我们怎么去控制绘制的区域呢?
我们的View显示区域,无非以下三种情况:

Android 高仿微信6.0主界面 带你玩转切换图标变色

针对这三种情况,我门的图标的边长应该是什么呢?

我觉得边长应该是:控件的高度-文本的高度-内边距   与  控件的宽度-内边距  两者的小值;大家仔细推敲一下;

好了,有了上面的边长的结论,我们就开始计算图标的绘制范围了:

[java] view plain copy print?
  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
  3. {  
  4.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.   
  6.     // 得到绘制icon的宽  
  7.     int bitmapWidth = Math.min(getMeasuredWidth() - getPaddingLeft()  
  8.             - getPaddingRight(), getMeasuredHeight() - getPaddingTop()  
  9.             - getPaddingBottom() - mTextBound.height());  
  10.   
  11.     int left = getMeasuredWidth() / 2 - bitmapWidth / 2;  
  12.     int top = (getMeasuredHeight() - mTextBound.height()) / 2 - bitmapWidth  
  13.             / 2;  
  14.     // 设置icon的绘制范围  
  15.     mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth);  
  16.   
  17. }  
  @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        // 得到绘制icon的宽        int bitmapWidth = Math.min(getMeasuredWidth() - getPaddingLeft()                - getPaddingRight(), getMeasuredHeight() - getPaddingTop()                - getPaddingBottom() - mTextBound.height());        int left = getMeasuredWidth() / 2 - bitmapWidth / 2;        int top = (getMeasuredHeight() - mTextBound.height()) / 2 - bitmapWidth                / 2;        // 设置icon的绘制范围        mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth);    }

3、绘制图标

绘制图标有很多步骤呀,我来列一列

1、计算alpha(默认为0)

2、绘制原图

3、在绘图区域,绘制一个纯色块(设置了alpha),此步绘制在内存的bitmap上

4、设置mode,针对内存中的bitmap上的paint

5、绘制我们的图标,此步绘制在内存的bitmap上

6、绘制原文本

7、绘制设置alpha和颜色后的文本

8、将内存中的bitmap绘制出来

根据上面的步骤,可以看出来,我们的图标其实绘制了两次,为什么要绘制原图呢,因为我觉得比较好看。

3-5步骤,就是我们上面分析的原理

6-7步,是绘制文本,可以看到,我们的文本就是通过设置alpha实现的

[java] view plain copy print?
  1. @Override  
  2.     protected void onDraw(Canvas canvas)  
  3.     {  
  4.   
  5.         int alpha = (int) Math.ceil((255 * mAlpha));  
  6.         canvas.drawBitmap(mIconBitmap, null, mIconRect, null);  
  7.         setupTargetBitmap(alpha);  
  8.         drawSourceText(canvas, alpha);  
  9.         drawTargetText(canvas, alpha);  
  10.         canvas.drawBitmap(mBitmap, 00null);  
  11.   
  12.     }  
  13.       
  14.     private void setupTargetBitmap(int alpha)  
  15.     {  
  16.         mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),  
  17.                 Config.ARGB_8888);  
  18.         mCanvas = new Canvas(mBitmap);  
  19.         mPaint = new Paint();  
  20.         mPaint.setColor(mColor);  
  21.         mPaint.setAntiAlias(true);  
  22.         mPaint.setDither(true);  
  23.         mPaint.setAlpha(alpha);  
  24.         mCanvas.drawRect(mIconRect, mPaint);  
  25.         mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));  
  26.         mPaint.setAlpha(255);  
  27.         mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);  
  28.     }  
  29.   
  30.     private void drawSourceText(Canvas canvas, int alpha)  
  31.     {  
  32.         mTextPaint.setTextSize(mTextSize);  
  33.         mTextPaint.setColor(0xff333333);  
  34.         mTextPaint.setAlpha(255 - alpha);  
  35.         canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2  
  36.                 - mTextBound.width() / 2,  
  37.                 mIconRect.bottom + mTextBound.height(), mTextPaint);  
  38.     }  
  39.       
  40.     private void drawTargetText(Canvas canvas, int alpha)  
  41.     {  
  42.         mTextPaint.setColor(mColor);  
  43.         mTextPaint.setAlpha(alpha);  
  44.         canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2  
  45.                 - mTextBound.width() / 2,  
  46.                 mIconRect.bottom + mTextBound.height(), mTextPaint);  
  47.           
  48.     }  
@Override    protected void onDraw(Canvas canvas)    {        int alpha = (int) Math.ceil((255 * mAlpha));        canvas.drawBitmap(mIconBitmap, null, mIconRect, null);        setupTargetBitmap(alpha);        drawSourceText(canvas, alpha);        drawTargetText(canvas, alpha);        canvas.drawBitmap(mBitmap, 0, 0, null);    }    private void setupTargetBitmap(int alpha)    {        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),                Config.ARGB_8888);        mCanvas = new Canvas(mBitmap);        mPaint = new Paint();        mPaint.setColor(mColor);        mPaint.setAntiAlias(true);        mPaint.setDither(true);        mPaint.setAlpha(alpha);        mCanvas.drawRect(mIconRect, mPaint);        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));        mPaint.setAlpha(255);        mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);    }    private void drawSourceText(Canvas canvas, int alpha)    {        mTextPaint.setTextSize(mTextSize);        mTextPaint.setColor(0xff333333);        mTextPaint.setAlpha(255 - alpha);        canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2                - mTextBound.width() / 2,                mIconRect.bottom + mTextBound.height(), mTextPaint);    }    private void drawTargetText(Canvas canvas, int alpha)    {        mTextPaint.setColor(mColor);        mTextPaint.setAlpha(alpha);        canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2                - mTextBound.width() / 2,                mIconRect.bottom + mTextBound.height(), mTextPaint);    }

关于绘制文本区域的计算,首先是起点x:mIconRect.left + mIconRect.width() / 2- mTextBound.width() / 2 有点长哈,文本mIconRect.left + mIconRect.width() / 2这个位置,在图标水平区域的中心点,这个应该没有疑问;图标水平区域的中点- mTextBound.width() / 2 开始绘制文本,是不是就是居中在图标的下面;

有人可能会问:你怎么知道文本宽度小于图标,我有5个字咋办?5个字怎么了,照样是居中显示,不信你试试~~

4、公布设置透明度的方法

到此,我们的图标控件写完了,但是还没有把我们的控制icon的方法放出去:

[java] view plain copy print?
  1. public void setIconAlpha(float alpha)  
  2. {  
  3.     this.mAlpha = alpha;  
  4.     invalidateView();  
  5. }  
  6.   
  7. private void invalidateView()  
  8. {  
  9.     if (Looper.getMainLooper() == Looper.myLooper())  
  10.     {  
  11.         invalidate();  
  12.     } else  
  13.     {  
  14.         postInvalidate();  
  15.     }  
  16. }  
  public void setIconAlpha(float alpha)    {        this.mAlpha = alpha;        invalidateView();    }    private void invalidateView()    {        if (Looper.getMainLooper() == Looper.myLooper())        {            invalidate();        } else        {            postInvalidate();        }    }

我们叫做setIconAlpha,避免了和setAlpha冲突,设置完成后,invalidate一下~~~


到此就真的结束了,接下来看用法。


4、实战


1、布局文件

[html] view plain copy print?
  1. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     xmlns:zhy=“http://schemas.android.com/apk/res/com.zhy.weixin6.ui”  
  3.     xmlns:tools=“http://schemas.android.com/tools”  
  4.     android:layout_width=“match_parent”  
  5.     android:layout_height=“match_parent”  
  6.     android:orientation=“vertical” >  
  7.   
  8.     <android.support.v4.view.ViewPager  
  9.         android:id=“@+id/id_viewpager”  
  10.         android:layout_width=“fill_parent”  
  11.         android:layout_height=“0dp”  
  12.         android:layout_weight=“1” >  
  13.     </android.support.v4.view.ViewPager>  
  14.   
  15.     <LinearLayout  
  16.         android:layout_width=“fill_parent”  
  17.         android:layout_height=“60dp”  
  18.         android:background=“@drawable/tabbg”  
  19.         android:orientation=“horizontal” >  
  20.   
  21.         <com.zhy.weixin6.ui.ChangeColorIconWithTextView  
  22.             android:id=“@+id/id_indicator_one”  
  23.             android:layout_width=“0dp”  
  24.             android:layout_height=“fill_parent”  
  25.             android:layout_weight=“1”  
  26.             android:padding=“5dp”  
  27.             zhy:icon=“@drawable/ic_menu_start_conversation”  
  28.             zhy:text=“@string/tab_weixin”  
  29.             zhy:text_size=“12sp” />  
  30.   
  31.         <com.zhy.weixin6.ui.ChangeColorIconWithTextView  
  32.             android:id=“@+id/id_indicator_two”  
  33.             android:layout_width=“0dp”  
  34.             android:layout_height=“fill_parent”  
  35.             android:layout_weight=“1”  
  36.             android:padding=“5dp”  
  37.             zhy:icon=“@drawable/ic_menu_friendslist”  
  38.             zhy:text=“@string/tab_contact”  
  39.             zhy:text_size=“12sp” />  
  40.   
  41.         <com.zhy.weixin6.ui.ChangeColorIconWithTextView  
  42.             android:id=“@+id/id_indicator_three”  
  43.             android:layout_width=“0dp”  
  44.             android:layout_height=“fill_parent”  
  45.             android:layout_weight=“1”  
  46.             android:padding=“5dp”  
  47.             zhy:icon=“@drawable/ic_menu_emoticons”  
  48.             zhy:text=“@string/tab_find”  
  49.             zhy:text_size=“12sp” />  
  50.   
  51.         <com.zhy.weixin6.ui.ChangeColorIconWithTextView  
  52.             android:id=“@+id/id_indicator_four”  
  53.             android:layout_width=“0dp”  
  54.             android:layout_height=“fill_parent”  
  55.             android:layout_weight=“1”  
  56.             android:padding=“5dp”  
  57.             zhy:icon=“@drawable/ic_menu_allfriends”  
  58.             zhy:text=“@string/tab_me”  
  59.             zhy:text_size=“12sp” />  
  60.     </LinearLayout>  
  61.   
  62. </LinearLayout>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.weixin6.ui"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <android.support.v4.view.ViewPager        android:id="@+id/id_viewpager"        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="1" >    </android.support.v4.view.ViewPager>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="60dp"        android:background="@drawable/tabbg"        android:orientation="horizontal" >        <com.zhy.weixin6.ui.ChangeColorIconWithTextView            android:id="@+id/id_indicator_one"            android:layout_width="0dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:padding="5dp"            zhy:icon="@drawable/ic_menu_start_conversation"            zhy:text="@string/tab_weixin"            zhy:text_size="12sp" />        <com.zhy.weixin6.ui.ChangeColorIconWithTextView            android:id="@+id/id_indicator_two"            android:layout_width="0dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:padding="5dp"            zhy:icon="@drawable/ic_menu_friendslist"            zhy:text="@string/tab_contact"            zhy:text_size="12sp" />        <com.zhy.weixin6.ui.ChangeColorIconWithTextView            android:id="@+id/id_indicator_three"            android:layout_width="0dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:padding="5dp"            zhy:icon="@drawable/ic_menu_emoticons"            zhy:text="@string/tab_find"            zhy:text_size="12sp" />        <com.zhy.weixin6.ui.ChangeColorIconWithTextView            android:id="@+id/id_indicator_four"            android:layout_width="0dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:padding="5dp"            zhy:icon="@drawable/ic_menu_allfriends"            zhy:text="@string/tab_me"            zhy:text_size="12sp" />    </LinearLayout></LinearLayout>

2、MainActivity

[java] view plain copy print?
  1. package com.zhy.weixin6.ui;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.Method;  
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7.   
  8. import android.annotation.SuppressLint;  
  9. import android.os.Bundle;  
  10. import android.support.v4.app.Fragment;  
  11. import android.support.v4.app.FragmentActivity;  
  12. import android.support.v4.app.FragmentPagerAdapter;  
  13. import android.support.v4.view.ViewPager;  
  14. import android.support.v4.view.ViewPager.OnPageChangeListener;  
  15. import android.view.Menu;  
  16. import android.view.View;  
  17. import android.view.View.OnClickListener;  
  18. import android.view.ViewConfiguration;  
  19. import android.view.Window;  
  20.   
  21. @SuppressLint(“NewApi”)  
  22. public class MainActivity extends FragmentActivity implements  
  23.         OnPageChangeListener, OnClickListener  
  24. {  
  25.     private ViewPager mViewPager;  
  26.     private List<Fragment> mTabs = new ArrayList<Fragment>();  
  27.     private FragmentPagerAdapter mAdapter;  
  28.   
  29.     private String[] mTitles = new String[] { “First Fragment!”,  
  30.             ”Second Fragment!”“Third Fragment!”“Fourth Fragment!” };  
  31.   
  32.     private List<ChangeColorIconWithTextView> mTabIndicator = new ArrayList<ChangeColorIconWithTextView>();  
  33.   
  34.     @Override  
  35.     protected void onCreate(Bundle savedInstanceState)  
  36.     {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.activity_main);  
  39.   
  40.         setOverflowShowingAlways();  
  41.         getActionBar().setDisplayShowHomeEnabled(false);  
  42.         mViewPager = (ViewPager) findViewById(R.id.id_viewpager);  
  43.   
  44.         initDatas();  
  45.   
  46.         mViewPager.setAdapter(mAdapter);  
  47.         mViewPager.setOnPageChangeListener(this);  
  48.     }  
  49.   
  50.     private void initDatas()  
  51.     {  
  52.   
  53.         for (String title : mTitles)  
  54.         {  
  55.             TabFragment tabFragment = new TabFragment();  
  56.             Bundle args = new Bundle();  
  57.             args.putString(”title”, title);  
  58.             tabFragment.setArguments(args);  
  59.             mTabs.add(tabFragment);  
  60.         }  
  61.   
  62.         mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())  
  63.         {  
  64.   
  65.             @Override  
  66.             public int getCount()  
  67.             {  
  68.                 return mTabs.size();  
  69.             }  
  70.   
  71.             @Override  
  72.             public Fragment getItem(int arg0)  
  73.             {  
  74.                 return mTabs.get(arg0);  
  75.             }  
  76.         };  
  77.   
  78.         initTabIndicator();  
  79.   
  80.     }  
  81.   
  82.     @Override  
  83.     public boolean onCreateOptionsMenu(Menu menu)  
  84.     {  
  85.         getMenuInflater().inflate(R.menu.main, menu);  
  86.         return true;  
  87.     }  
  88.   
  89.     private void initTabIndicator()  
  90.     {  
  91.         ChangeColorIconWithTextView one = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_one);  
  92.         ChangeColorIconWithTextView two = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_two);  
  93.         ChangeColorIconWithTextView three = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_three);  
  94.         ChangeColorIconWithTextView four = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_four);  
  95.   
  96.         mTabIndicator.add(one);  
  97.         mTabIndicator.add(two);  
  98.         mTabIndicator.add(three);  
  99.         mTabIndicator.add(four);  
  100.   
  101.         one.setOnClickListener(this);  
  102.         two.setOnClickListener(this);  
  103.         three.setOnClickListener(this);  
  104.         four.setOnClickListener(this);  
  105.   
  106.         one.setIconAlpha(1.0f);  
  107.     }  
  108.   
  109.     @Override  
  110.     public void onPageSelected(int arg0)  
  111.     {  
  112.     }  
  113.   
  114.     @Override  
  115.     public void onPageScrolled(int position, float positionOffset,  
  116.             int positionOffsetPixels)  
  117.     {  
  118.         // Log.e(“TAG”, “position = ” + position + ” , positionOffset = ”  
  119.         // + positionOffset);  
  120.   
  121.         if (positionOffset > 0)  
  122.         {  
  123.             ChangeColorIconWithTextView left = mTabIndicator.get(position);  
  124.             ChangeColorIconWithTextView right = mTabIndicator.get(position + 1);  
  125.   
  126.             left.setIconAlpha(1 - positionOffset);  
  127.             right.setIconAlpha(positionOffset);  
  128.         }  
  129.   
  130.     }  
  131.   
  132.     @Override  
  133.     public void onPageScrollStateChanged(int state)  
  134.     {  
  135.   
  136.     }  
  137.   
  138.     @Override  
  139.     public void onClick(View v)  
  140.     {  
  141.   
  142.         resetOtherTabs();  
  143.   
  144.         switch (v.getId())  
  145.         {  
  146.         case R.id.id_indicator_one:  
  147.             mTabIndicator.get(0).setIconAlpha(1.0f);  
  148.             mViewPager.setCurrentItem(0false);  
  149.             break;  
  150.         case R.id.id_indicator_two:  
  151.             mTabIndicator.get(1).setIconAlpha(1.0f);  
  152.             mViewPager.setCurrentItem(1false);  
  153.             break;  
  154.         case R.id.id_indicator_three:  
  155.             mTabIndicator.get(2).setIconAlpha(1.0f);  
  156.             mViewPager.setCurrentItem(2false);  
  157.             break;  
  158.         case R.id.id_indicator_four:  
  159.             mTabIndicator.get(3).setIconAlpha(1.0f);  
  160.             mViewPager.setCurrentItem(3false);  
  161.             break;  
  162.   
  163.         }  
  164.   
  165.     }  
  166.   
  167.     /** 
  168.      * 重置其他的Tab 
  169.      */  
  170.     private void resetOtherTabs()  
  171.     {  
  172.         for (int i = 0; i < mTabIndicator.size(); i++)  
  173.         {  
  174.             mTabIndicator.get(i).setIconAlpha(0);  
  175.         }  
  176.     }  
  177.   
  178.     @Override  
  179.     public boolean onMenuOpened(int featureId, Menu menu)  
  180.     {  
  181.         if (featureId == Window.FEATURE_ACTION_BAR && menu != null)  
  182.         {  
  183.             if (menu.getClass().getSimpleName().equals(“MenuBuilder”))  
  184.             {  
  185.                 try  
  186.                 {  
  187.                     Method m = menu.getClass().getDeclaredMethod(  
  188.                             ”setOptionalIconsVisible”, Boolean.TYPE);  
  189.                     m.setAccessible(true);  
  190.                     m.invoke(menu, true);  
  191.                 } catch (Exception e)  
  192.                 {  
  193.                 }  
  194.             }  
  195.         }  
  196.         return super.onMenuOpened(featureId, menu);  
  197.     }  
  198.   
  199.     private void setOverflowShowingAlways()  
  200.     {  
  201.         try  
  202.         {  
  203.             // true if a permanent menu key is present, false otherwise.  
  204.             ViewConfiguration config = ViewConfiguration.get(this);  
  205.             Field menuKeyField = ViewConfiguration.class  
  206.                     .getDeclaredField(”sHasPermanentMenuKey”);  
  207.             menuKeyField.setAccessible(true);  
  208.             menuKeyField.setBoolean(config, false);  
  209.         } catch (Exception e)  
  210.         {  
  211.             e.printStackTrace();  
  212.         }  
  213.     }  
  214.   
  215. }  
package com.zhy.weixin6.ui;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import android.annotation.SuppressLint;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.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewConfiguration;import android.view.Window;@SuppressLint("NewApi")public class MainActivity extends FragmentActivity implements        OnPageChangeListener, OnClickListener{    private ViewPager mViewPager;    private List<Fragment> mTabs = new ArrayList<Fragment>();    private FragmentPagerAdapter mAdapter;    private String[] mTitles = new String[] { "First Fragment!",            "Second Fragment!", "Third Fragment!", "Fourth Fragment!" };    private List<ChangeColorIconWithTextView> mTabIndicator = new ArrayList<ChangeColorIconWithTextView>();    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        setOverflowShowingAlways();        getActionBar().setDisplayShowHomeEnabled(false);        mViewPager = (ViewPager) findViewById(R.id.id_viewpager);        initDatas();        mViewPager.setAdapter(mAdapter);        mViewPager.setOnPageChangeListener(this);    }    private void initDatas()    {        for (String title : mTitles)        {            TabFragment tabFragment = new TabFragment();            Bundle args = new Bundle();            args.putString("title", title);            tabFragment.setArguments(args);            mTabs.add(tabFragment);        }        mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())        {            @Override            public int getCount()            {                return mTabs.size();            }            @Override            public Fragment getItem(int arg0)            {                return mTabs.get(arg0);            }        };        initTabIndicator();    }    @Override    public boolean onCreateOptionsMenu(Menu menu)    {        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    private void initTabIndicator()    {        ChangeColorIconWithTextView one = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_one);        ChangeColorIconWithTextView two = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_two);        ChangeColorIconWithTextView three = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_three);        ChangeColorIconWithTextView four = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_four);        mTabIndicator.add(one);        mTabIndicator.add(two);        mTabIndicator.add(three);        mTabIndicator.add(four);        one.setOnClickListener(this);        two.setOnClickListener(this);        three.setOnClickListener(this);        four.setOnClickListener(this);        one.setIconAlpha(1.0f);    }    @Override    public void onPageSelected(int arg0)    {    }    @Override    public void onPageScrolled(int position, float positionOffset,            int positionOffsetPixels)    {        // Log.e("TAG", "position = " + position + " , positionOffset = "        // + positionOffset);        if (positionOffset > 0)        {            ChangeColorIconWithTextView left = mTabIndicator.get(position);            ChangeColorIconWithTextView right = mTabIndicator.get(position + 1);            left.setIconAlpha(1 - positionOffset);            right.setIconAlpha(positionOffset);        }    }    @Override    public void onPageScrollStateChanged(int state)    {    }    @Override    public void onClick(View v)    {        resetOtherTabs();        switch (v.getId())        {        case R.id.id_indicator_one:            mTabIndicator.get(0).setIconAlpha(1.0f);            mViewPager.setCurrentItem(0, false);            break;        case R.id.id_indicator_two:            mTabIndicator.get(1).setIconAlpha(1.0f);            mViewPager.setCurrentItem(1, false);            break;        case R.id.id_indicator_three:            mTabIndicator.get(2).setIconAlpha(1.0f);            mViewPager.setCurrentItem(2, false);            break;        case R.id.id_indicator_four:            mTabIndicator.get(3).setIconAlpha(1.0f);            mViewPager.setCurrentItem(3, false);            break;        }    }    /**     * 重置其他的Tab     */    private void resetOtherTabs()    {        for (int i = 0; i < mTabIndicator.size(); i++)        {            mTabIndicator.get(i).setIconAlpha(0);        }    }    @Override    public boolean onMenuOpened(int featureId, Menu menu)    {        if (featureId == Window.FEATURE_ACTION_BAR && menu != null)        {            if (menu.getClass().getSimpleName().equals("MenuBuilder"))            {                try                {                    Method m = menu.getClass().getDeclaredMethod(                            "setOptionalIconsVisible", Boolean.TYPE);                    m.setAccessible(true);                    m.invoke(menu, true);                } catch (Exception e)                {                }            }        }        return super.onMenuOpened(featureId, menu);    }    private void setOverflowShowingAlways()    {        try        {            // true if a permanent menu key is present, false otherwise.            ViewConfiguration config = ViewConfiguration.get(this);            Field menuKeyField = ViewConfiguration.class                    .getDeclaredField("sHasPermanentMenuKey");            menuKeyField.setAccessible(true);            menuKeyField.setBoolean(config, false);        } catch (Exception e)        {            e.printStackTrace();        }    }}

Activity里面代码虽然没什么注释,但是很简单哈,就是初始化Fragment,得到我们的适配器,然后设置给ViewPager;

initTabIndicator我们初始化我们的自定义控件,以及加上了点击事件;

唯一一个需要指出的就是:

我们在onPageScrolled中,动态的获取position以及positionOffset,然后拿到左右两个View,设置positionOffset ;

这里表示下惭愧,曾经在高仿微信5.2.1主界面架构 包含消息通知 的onPageScrolled中写了一堆的if else,在视频上线后,也有同学立马就提出了,一行代码搞定~~

所以,我们这里简单找了下规律,已经没有if else的身影了~~~

还剩两个反射的方法,是控制Actionbar的图标的,和点击menu按键,将ActionBar的menu显示在正常区域的~~

3、TabFragment

[java] view plain copy print?
  1. package com.zhy.weixin6.ui;  
  2.   
  3. import android.graphics.Color;  
  4. import android.os.Bundle;  
  5. import android.support.v4.app.Fragment;  
  6. import android.view.Gravity;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.view.ViewGroup;  
  10. import android.widget.TextView;  
  11.   
  12. public class TabFragment extends Fragment  
  13. {  
  14.     private String mTitle = “Default”;  
  15.       
  16.   
  17.     public TabFragment()  
  18.     {  
  19.     }  
  20.   
  21.     @Override  
  22.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  23.             Bundle savedInstanceState)  
  24.     {  
  25.         if (getArguments() != null)  
  26.         {  
  27.             mTitle = getArguments().getString(”title”);  
  28.         }  
  29.   
  30.         TextView textView = new TextView(getActivity());  
  31.         textView.setTextSize(20);  
  32.         textView.setBackgroundColor(Color.parseColor(”#ffffffff”));  
  33.         textView.setGravity(Gravity.CENTER);  
  34.         textView.setText(mTitle);  
  35.         return textView;  
  36.     }  
  37. }  
package com.zhy.weixin6.ui;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{    private String mTitle = "Default";    public TabFragment()    {    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState)    {        if (getArguments() != null)        {            mTitle = getArguments().getString("title");        }        TextView textView = new TextView(getActivity());        textView.setTextSize(20);        textView.setBackgroundColor(Color.parseColor("#ffffffff"));        textView.setGravity(Gravity.CENTER);        textView.setText(mTitle);        return textView;    }}



好了,到此我们的整个案例就结束了~~

大家可以在布局文件中设置各种颜色,4个不同颜色也可以,尽情的玩耍吧~~



源码点击下载





建了一个QQ群,方便大家交流。群号:55032675

———————————————————————————————————-

博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

1、Android 自定义控件实战 电商活动中的刮刮卡

2、android自定义控件实战  打造Android流式布局和热门标签

3、Android智能机器人“小慕”的实现

4、高仿QQ5.0侧滑

5、高仿微信5.2.1主界面及消息提醒