Android 微信6.1 tab欄圖標(biāo)和字體顏色漸變的實現(xiàn)
相信大家都見到了微信圖標(biāo)顏色漸變的過程,是不是感覺很牛?不得不說微信團(tuán)隊確實是很厲害的團(tuán)隊,不管是從設(shè)計還是開發(fā)人員。
今天我?guī)Т蠹襾砜纯?,微?tab 欄圖標(biāo)和字體顏色漸變的過程。先上圖吧!今天學(xué)了一招制作 gif 動態(tài)圖的快捷方法。剛好用的上,以前一直想寫點什么東西,
苦于一直不知道怎么生成動態(tài)圖,現(xiàn)在終于學(xué)會了,哈哈,讓我偷偷的樂一會。額,還是上圖吧。。。

好了,效果圖也看到了,那么我也就不多啰嗦了,直接進(jìn)入主題,看代碼
[java] view plain copy
package moon.wechat.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
/**
* Created by moon.zhong on 2015/2/4.
*/
public class TabItem extends View {
/*字體大小*/
private int mTextSize ;
/*字體選中的顏色*/
private int mTextColorSelect ;
/*字體未選擇的時候的顏色*/
private int mTextColorNormal;
/*繪制未選中時字體的畫筆*/
private Paint mTextPaintNormal;
/*繪制已選中時字體的畫筆*/
private Paint mTextPaintSelect;
/*每個 item 的寬和高,包括字體和圖標(biāo)一起*/
private int mViewHeight, mViewWidth;
/*字體的內(nèi)容*/
private String mTextValue ;
/*已選中時的圖標(biāo)*/
private Bitmap mIconNormal;
/*未選中時的圖標(biāo)*/
private Bitmap mIconSelect;
/*用于記錄字體大小*/
private Rect mBoundText;
/*已選中是圖標(biāo)的畫筆*/
private Paint mIconPaintSelect;
/*為選中時圖標(biāo)的畫筆*/
private Paint mIconPaintNormal;
public TabItem(Context context) {
this(context, null);
}
public TabItem(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
initText();
}
/*初始化一些東西*/
private void initView() {
mBoundText = new Rect();
}
/*初始化畫筆,并設(shè)置出是內(nèi)容*/
private void initText() {
mTextPaintNormal = new Paint();
mTextPaintNormal.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics()));
mTextPaintNormal.setColor(mTextColorNormal);
mTextPaintNormal.setAntiAlias(true);
mTextPaintNormal.setAlpha(0xff);
mTextPaintSelect = new Paint();
mTextPaintSelect.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics()));
mTextPaintSelect.setColor(mTextColorSelect);
mTextPaintSelect.setAntiAlias(true);
mTextPaintSelect.setAlpha(0);
mIconPaintSelect = new Paint(Paint.ANTI_ALIAS_FLAG) ;
mIconPaintSelect.setAlpha(0);
mIconPaintNormal = new Paint(Paint.ANTI_ALIAS_FLAG) ;
mIconPaintNormal.setAlpha(0xff);
}
/*測量字體的大小*/
private void measureText() {
mTextPaintNormal.getTextBounds(mTextValue, 0, mTextValue.length(), mBoundText);
}
/*測量字體和圖標(biāo)的大小,并設(shè)置自身的寬和高*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0, height = 0;
measureText();
int contentWidth = Math.max(mBoundText.width(), mIconNormal.getWidth());
int desiredWidth = getPaddingLeft() + getPaddingRight() + contentWidth;
switch (widthMode) {
case MeasureSpec.AT_MOST:
width = Math.min(widthSize, desiredWidth);
break;
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.UNSPECIFIED:
width = desiredWidth;
break;
}
int contentHeight = mBoundText.height() + mIconNormal.getHeight();
int desiredHeight = getPaddingTop() + getPaddingBottom() + contentHeight;
switch (heightMode) {
case MeasureSpec.AT_MOST:
height = Math.min(heightSize, desiredHeight);
break;
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.UNSPECIFIED:
height = contentHeight;
break;
}
setMeasuredDimension(width, height);
mViewWidth = getMeasuredWidth() ;
mViewHeight = getMeasuredHeight() ;
}
@Override
protected void onDraw(Canvas canvas) {
drawBitmap(canvas) ;
drawText(canvas) ;
}
/*話圖標(biāo),先畫為選中的圖標(biāo),在畫已選中的圖標(biāo)*/
private void drawBitmap(Canvas canvas) {
int left = (mViewWidth - mIconNormal.getWidth())/2 ;
int top = (mViewHeight - mIconNormal.getHeight() - mBoundText.height()) /2 ;
canvas.drawBitmap(mIconNormal, left, top ,mIconPaintNormal);
canvas.drawBitmap(mIconSelect, left, top , mIconPaintSelect);
}
/*畫字體*/
private void drawText(Canvas canvas) {
float x = (mViewWidth - mBoundText.width())/2.0f ;
float y = (mViewHeight + mIconNormal.getHeight() + mBoundText.height()) /2.0F ;
canvas.drawText(mTextValue,x,y, mTextPaintNormal);
canvas.drawText(mTextValue,x,y, mTextPaintSelect);
}
public void setTextSize(int textSize) {
this.mTextSize = textSize;
mTextPaintNormal.setTextSize(textSize);
mTextPaintSelect.setTextSize(textSize);
}
public void setTextColorSelect(int mTextColorSelect) {
this.mTextColorSelect = mTextColorSelect;
mTextPaintSelect.setColor(mTextColorSelect);
mTextPaintSelect.setAlpha(0);
}
public void setTextColorNormal(int mTextColorNormal) {
this.mTextColorNormal = mTextColorNormal;
mTextPaintNormal.setColor(mTextColorNormal);
mTextPaintNormal.setAlpha(0xff);
}
public void setTextValue(String TextValue) {
this.mTextValue = TextValue;
}
public void setIconText(int[] iconSelId,String TextValue) {
this.mIconSelect = BitmapFactory.decodeResource(getResources(), iconSelId[0]);
this.mIconNormal = BitmapFactory.decodeResource(getResources(), iconSelId[1]);
this.mTextValue = TextValue;
}
/*通過 alpha 來設(shè)置 每個畫筆的透明度,從而實現(xiàn)現(xiàn)實的效果*/
public void setTabAlpha(float alpha){
int paintAlpha = (int)(alpha*255) ;
mIconPaintSelect.setAlpha(paintAlpha);
mIconPaintNormal.setAlpha(255-paintAlpha);
mTextPaintSelect.setAlpha(paintAlpha);
mTextPaintNormal.setAlpha(255-paintAlpha);
invalidate();
}
}
分析: 以上代碼,功能實現(xiàn) tab 的每個 item 的內(nèi)容,在微信的項目中也就是,一個圖標(biāo)加一個字體,
關(guān)鍵代碼就在public void setTabAlpha(float alpha) 這個方法,此方法是 viewPager 切換 item 時,不斷改變偏移量來調(diào)用,從而不斷改變
每個畫筆的透明度,實現(xiàn)圖標(biāo)和顏色的漸變;是不是很簡單?到這里其實我們顏色漸變的代碼就已經(jīng)實現(xiàn)了。接下來的內(nèi)容可以忽略
這樣我們只需要在 MainActivity 的 xml 中定義一個線性布局,然后放如四個我們自定義的 View 進(jìn)去,就可以了。但是這樣你就滿足了嗎?
我先來給你們看看我的MainActivity的代碼;
[java] view plain copy
package moon.wechat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import java.util.HashMap;
import java.util.Map;
import moon.wechat.view.TabView;
public class MainActivity extends ActionBarActivity {
private String[] mTitle = {"微信", "通訊錄", "發(fā)現(xiàn)", "我"};
private int[] mIconSelect = {R.drawable.al_, R.drawable.al8, R.drawable.alb, R.drawable.ald};
private int[] mIconNormal = {R.drawable.ala, R.drawable.al9, R.drawable.alc, R.drawable.ale};
private ViewPager mViewPager ;
private TabView mTabView ;
private Map<Integer,Fragment> mFragmentMap ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFragmentMap = new HashMap<>() ;
mViewPager = (ViewPager)findViewById(R.id.id_view_pager) ;
mViewPager.setOffscreenPageLimit(4);
mViewPager.setAdapter(new PageAdapter(getSupportFragmentManager()));
mTabView = (TabView)findViewById(R.id.id_tab) ;
mTabView.setViewPager(mViewPager);
}
private Fragment getFragment(int position){
Fragment fragment = mFragmentMap.get(position) ;
if(fragment == null){
switch (position){
case 0:
fragment = new WeChatFragment() ;
break ;
case 1:
fragment = new WeContactFragment();
break ;
case 2:
fragment = new WeDiscoverFragment();
break;
case 3:
fragment = new GameFragment() ;
// fragment = new WeMineFragment();
break;
}
mFragmentMap.put(position,fragment) ;
}
return fragment ;
}
class PageAdapter extends FragmentPagerAdapter implements TabView.OnItemIconTextSelectListener{
public PageAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return getFragment(position);
}
@Override
public int[] onIconSelect(int position) {
int icon[] = new int[2] ;
icon[0] = mIconSelect[position] ;
icon[1] = mIconNormal[position] ;
return icon;
}
@Override
public String onTextSelect(int position) {
return mTitle[position];
}
@Override
public int getCount() {
return mTitle.length;
}
}
}
是不是很簡單,而 xml 更簡單
[html] view plain copy
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zgy="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/id_view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
>
</android.support.v4.view.ViewPager>
<moon.wechat.view.TabView
android:id="@+id/id_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#eeeeee"
zgy:text_size="12sp"
zgy:text_normal_color="#ff777777"
zgy:text_select_color="#ff45c01a"
zgy:item_padding="7dp">
</moon.wechat.view.TabView>
</LinearLayout>
可以看到?jīng)]有定義我們剛剛自定義的 TabItem,而是使用的 TabView,那 TabView 到底是啥東西?相信大家都想到了,TabView 其實就是我們自定義的線性布局,
[java] view plain copy
package moon.wechat.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
import moon.wechat.R;
/**
* Created by moon.zhong on 2015/2/4.
*/
public class TabView extends LinearLayout implements View.OnClickListener {
private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mOnPageChangeListener;
private PagerAdapter mPagerAdapter;
private int mChildSize;
private List<TabItem> mTabItems;
private OnItemIconTextSelectListener mListener;
private int mTextSize = 12;
private int mTextColorSelect = 0xff45c01a;
private int mTextColorNormal = 0xff777777;
private int mPadding = 10;
public TabView(Context context) {
this(context, null);
}
public TabView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.TabView);
int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
switch (typedArray.getIndex(i)) {
case R.styleable.TabView_text_size:
mTextSize = (int) typedArray.getDimension(i, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
mTextSize, getResources().getDisplayMetrics()));
break;
case R.styleable.TabView_text_normal_color:
mTextColorNormal = typedArray.getColor(i, mTextColorNormal);
break;
case R.styleable.TabView_text_select_color:
mTextColorSelect = typedArray.getColor(i, mTextColorSelect);
break;
case R.styleable.TabView_item_padding:
mPadding = (int) typedArray.getDimension(i, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
mPadding, getResources().getDisplayMetrics()));
break;
}
}
typedArray.recycle();
mTabItems = new ArrayList<>();
}
public void setViewPager(final ViewPager mViewPager) {
if (mViewPager == null) {
return;
}
this.mViewPager = mViewPager;
this.mPagerAdapter = mViewPager.getAdapter();
if (this.mPagerAdapter == null) {
throw new RuntimeException("親,在您設(shè)置TabView的ViewPager時,請先設(shè)置ViewPager的PagerAdapter");
}
this.mChildSize = this.mPagerAdapter.getCount();
this.mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Log.v("zgy","=============position="+position+",====positionOffset="+positionOffset) ;
View leftView;
View rightView;
if (positionOffset > 0) {
leftView = mViewPager.getChildAt(position);
rightView = mViewPager.getChildAt(position + 1);
leftView.setAlpha(1 - positionOffset);
rightView.setAlpha(positionOffset);
mTabItems.get(position).setTabAlpha(1 - positionOffset);
mTabItems.get(position + 1).setTabAlpha(positionOffset);
} else {
mViewPager.getChildAt(position).setAlpha(1);
mTabItems.get(position).setTabAlpha(1 - positionOffset);
}
if (mOnPageChangeListener != null) {
mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageSelected(int position) {
if (mOnPageChangeListener != null) {
mOnPageChangeListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mOnPageChangeListener != null) {
mOnPageChangeListener.onPageScrollStateChanged(state);
}
}
});
if (mPagerAdapter instanceof OnItemIconTextSelectListener) {
mListener = (OnItemIconTextSelectListener) mPagerAdapter;
}else {
throw new RuntimeException("請讓你的pageAdapter實現(xiàn)OnItemIconTextSelectListener接口");
}
initItem();
}
public void setOnPageChangeListener(ViewPager.OnPageChangeListener mOnPageChangeListener) {
this.mOnPageChangeListener = mOnPageChangeListener;
}
private void initItem() {
for (int i = 0; i < mChildSize; i++) {
TabItem tabItem = new TabItem(getContext());
LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
tabItem.setPadding(mPadding, mPadding, mPadding, mPadding);
tabItem.setIconText(mListener.onIconSelect(i), mListener.onTextSelect(i));
tabItem.setTextSize(mTextSize);
tabItem.setTextColorNormal(mTextColorNormal);
tabItem.setTextColorSelect(mTextColorSelect);
tabItem.setLayoutParams(params);
tabItem.setTag(i);
tabItem.setOnClickListener(this);
mTabItems.add(tabItem);
addView(tabItem);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void onClick(View v) {
int position = (Integer) v.getTag();
if (mViewPager.getCurrentItem() == position) {
return;
}
for (TabItem tabItem : mTabItems) {
tabItem.setTabAlpha(0);
}
mTabItems.get(position).setTabAlpha(1);
mViewPager.setCurrentItem(position, false);
}
public interface OnItemIconTextSelectListener {
int[] onIconSelect(int position);
String onTextSelect(int position);
}
}
注釋有點少,額,不是少,是壓根就沒有,其實,這個類的代碼不需要注釋,我相信大家都能看懂,我就講下他的作用吧,
- 添加 item
- 監(jiān)聽 ViewPager 的滾動事件,從而設(shè)置相應(yīng) item 之間的顏色漸變,
- 設(shè)置相應(yīng) ViewPage 的透明度
- 為 TabItem 設(shè)置監(jiān)聽事件,
其實上面很多功能本來是在 MainActivity 中實現(xiàn)的,為了減少 Activity 內(nèi)部的代碼量,抽取出來,到達(dá)低耦合,高內(nèi)聚的效果。
Ok,以上就是 微信6.1 tab 欄顏色漸變效果的實現(xiàn)全過程。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
Android編程Widget創(chuàng)建與使用方法簡明教程
這篇文章主要介紹了Android編程Widget創(chuàng)建與使用方法,結(jié)合實例形式分析了Widget的功能、使用方法與相關(guān)注意事項,需要的朋友可以參考下2016-10-10
基于TransactionTooLargeException異常分析
下面小編就為大家分享一篇基于TransactionTooLargeException異常分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11
Android開發(fā)Jetpack組件Lifecycle使用篇
這一篇文章來介紹Android?Jetpack架構(gòu)組件的Lifecycle;?Lifecycle用于幫助開發(fā)者管理Activity和Fragment?的生命周期,?由于Lifecycle是LiveData和ViewModel的基礎(chǔ);所以需要先學(xué)習(xí)它2022-08-08
Android使用Intent傳大數(shù)據(jù)簡單實現(xiàn)詳解
這篇文章主要為大家介紹了Android使用Intent傳大數(shù)據(jù)簡單實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

