Android 微信6.1 tab栏图标和字体颜色渐变的实现
相信大家都见到了微信图标颜色渐变的过程,是不是感觉很牛逼?不得不说微信团队确实是很厉害的团队,不管是从设计还是开发人员。
今天我带大家来看看,微信 tab 栏图标和字体颜色渐变的过程。先上图吧!今天学了一招制作 gif 动态图的快捷方法。刚好用的上,以前一直想写点什么东西,
苦于一直不知道怎么生成动态图,现在终于学会了,哈哈,让我偷偷的乐一会。额,还是上图吧。。。
好了,效果图也看到了,那么我也就不多啰嗦了,直接进入主题,看代码
[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;
public class TabItem extends View {
private int mTextSize ;
private int mTextColorSelect ;
private int mTextColorNormal;
private Paint mTextPaintNormal;
private Paint mTextPaintSelect;
private int mViewHeight, mViewWidth;
private String mTextValue ;
private Bitmap mIconNormal;
private Bitmap mIconSelect;
private Rect mBoundText;
private Paint mIconPaintSelect;
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();
}
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);
}
@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) ;
}
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;
}
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();
}
}
分析: 以上代码,功能实现 tab 的每个 item 的内容,在微信的项目中也就是,一个图标加一个字体,
关键代码就在public void setTabAlpha(float alpha) 这个方法,此方法是 viewPager 切换 item 时,不断改变偏移量来调用,从而不断改变
每个画笔的透明度,实现图标和颜色的渐变;是不是很简单?到这里其实我们颜色渐变的代码就已经实现了。接下来的内容可以忽略
这样我们只需要在 MainActivity 的 xml 中定义一个线性布局,然后放如四个我们自定义的 View 进去,就可以了。但是这样你就满足了吗?
我先来给你们看看我的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 = {"微信", "通讯录", "发现", "我"};
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>
可以看到没有定义我们刚刚自定义的 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;
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("亲,在您设置TabView的ViewPager时,请先设置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实现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 监听 ViewPager 的滚动事件,从而设置相应 item 之间的颜色渐变, 设置相应 ViewPage 的透明度 为 TabItem 设置监听事件,其实上面很多功能本来是在 MainActivity 中实现的,为了减少 Activity 内部的代码量,抽取出来,到达低耦合,高内聚的效果。
Ok,以上就是 微信6.1 tab 栏颜色渐变效果的实现全过程。
您可能感兴趣的文章:Android 图片的颜色处理实例代码Android编程之图片颜色处理方法Android开发中使用颜色矩阵改变图片颜色,透明度及亮度的方法android中实现背景图片颜色渐变方法android开发修改状态栏背景色和图标颜色的示例Android实现修改状态栏背景、字体和图标颜色的方法Android 改变图标原有颜色和搜索框的实例代码Android编程实现图片的颜色处理功能示例
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341