欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 微信6.1 tab栏图标和字体颜色渐变的实现

程序员文章站 2024-02-22 17:15:23
相信大家都见到了微信图标颜色渐变的过程,是不是感觉很牛逼?不得不说微信团队确实是很厉害的团队,不管是从设计还是开发人员。 今天我带大家来看看,微信 tab 栏图标和字体颜...

相信大家都见到了微信图标颜色渐变的过程,是不是感觉很牛逼?不得不说微信团队确实是很厉害的团队,不管是从设计还是开发人员。

今天我带大家来看看,微信 tab 栏图标和字体颜色渐变的过程。先上图吧!今天学了一招制作 gif 动态图的快捷方法。刚好用的上,以前一直想写点什么东西,

苦于一直不知道怎么生成动态图,现在终于学会了,哈哈,让我偷偷的乐一会。额,还是上图吧。。。

Android 微信6.1 tab栏图标和字体颜色渐变的实现

好了,效果图也看到了,那么我也就不多啰嗦了,直接进入主题,看代码

[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 的宽和高,包括字体和图标一起*/ 
  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; 
  } 
  /*通过 alpha 来设置 每个画笔的透明度,从而实现现实的效果*/ 
  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; 
/** 
 * 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("亲,在您设置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); 
  } 
} 

注释有点少,额,不是少,是压根就没有,其实,这个类的代码不需要注释,我相信大家都能看懂,我就讲下他的作用吧,

  1. 添加 item
  2. 监听 viewpager 的滚动事件,从而设置相应 item 之间的颜色渐变,
  3. 设置相应 viewpage 的透明度
  4. 为 tabitem 设置监听事件,

其实上面很多功能本来是在 mainactivity 中实现的,为了减少 activity 内部的代码量,抽取出来,到达低耦合,高内聚的效果。

ok,以上就是 微信6.1 tab 栏颜色渐变效果的实现全过程。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!