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

Android实现微信首页左右滑动切换效果

程序员文章站 2024-03-05 17:27:49
大家看到微信首页切换效果有没有觉得很炫,滑动切换,点击底部bar瞬间切换,滑动切换渐变效果,线上效果图: 之前也在博客上看到别人的实现,再次基础上,我做了些优化。...

大家看到微信首页切换效果有没有觉得很炫,滑动切换,点击底部bar瞬间切换,滑动切换渐变效果,线上效果图:

Android实现微信首页左右滑动切换效果

之前也在博客上看到别人的实现,再次基础上,我做了些优化。首先说下实现原理,大神略过,o(╯□╰)o
页面上看到的三个页面是三个fragment, 左右滑动使用viewpager,相信大家也都是这么再用,那么底部用的是什么技术呢,底部渐变其实就是重写了imageview,以及在左右滑动时,改变了textview的颜色值,是不是很简单...下面我们一步一步的来: 

1.自定义imageview: 

 /**
  * 初始化资源图片bitmap及相关绘制对象
  * @param normal normals
  * @param selected focus
  */
 public final void init(int normal, int selected, int width, int height) {
  this.mnormalicon = createbitmap(normal);
  this.mselectedicon = createbitmap(selected);
  this.mnormalrect = new rect(0, 0, width, height);
  this.mselectedrect = new rect(0, 0, width, height);
  this.mpaint = new paint(1);
 }

这里定义了两个bitmap,分别对应获得焦点和失去焦点时显示的bitmap图像,两个矩阵,在绘制过程中使用到,定义了一个外部调用的方法,在左右滑动过程中,通过偏移值改变透明值,两张图片叠加就是对应的过度效果。

然后通通过滑动过程中不断刷新view完成重新绘制,由此有了重写ondraw方法: 

 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  if (this.mpaint == null) {
   return;
  }
  this.mpaint.setalpha(255 - this.mselectedalpha);
  canvas.drawbitmap(this.mnormalicon, null, this.mnormalrect, this.mpaint);
  this.mpaint.setalpha(this.mselectedalpha);
  canvas.drawbitmap(this.mselectedicon, null, this.mselectedrect, this.mpaint);
 }

这里可以看到同伙paint改变传入的两个bitmap透明度,从而达到渐变效果,其中mselectedalpha为外部传入透明值 

2.自定义实现底部bar容器,这里通过重写linearlayout实现(姑且叫做container),  在container中我们要做这么几件事:
1).定义外表调用接口,接收底部显示资源信息:
a.首先是初始化参数: 

public void initcontainer (string[] titles, int[][] iconsres, int[] colors, boolean showtransitioncolor) {
  this.mtitles = titles;
  this.miconres = iconsres;
  this.mtextnormalcolor = getresources().getcolor(colors[0]);
  this.mtextselectedcolor = getresources().getcolor(colors[1]);
  this.mshowtransitioncolor = showtransitioncolor;
 }

这里传入了tab显示的文字数组、显示的图片资源数组、默认颜色和获得焦点时颜色值数组(数组大小=2),以及切换时是否显示过渡效果

b.设置布局文件及布局文件里对应的控件id、显示图片时图片宽高参数,提供了三种方式:
 ①图文tab: 

/**
  * 设置布局文件及相关控件id
  * @param layout layout布局文件 id
  * @param iconid imageview 控件 id id <=0 时不显示
  * @param textid textview 控件 id id <=0 时不显示
  * @param width icon 宽度
  * @param height icon 高度
  */
 public void setcontainerlayout (int layout, int iconid, int textid, int width, int height) {
  mlayoutid = layout;
  mtextviewid = textid;
  miconviewid = iconid;
  miconwidth = width;
  miconheight = height;
 }

这里的layout及tab的布局文件, iconid对应的是自定义imageview的资源id, textid对应的是textview的id, 宽高指的是图片显示的宽高
②只有文字tab: 只显示文字tab时传入iconid即可
③只有图片tab: 相应的,是在图文tab提供的方法上,传入文本textid=0即可
c.注入viewpager:这里需要监听viewpager的滑动来改变渐变色

2).添加tab到容易container中:
这里需要判断iconid以及textid是否大于0,=0即不显示,同时为了居中平分底部container长度, 所有tab等分底部container 

/**
  * <p>添加tab view到当前容器</p>
  */
 private void addtabviewtocontainer() {
  final pageradapter adapter = mviewpager.getadapter(); 
  mtabview = new view[adapter.getcount()]; //这里根据adapter判断底部要显示的tab总数

  for (int index = 0, len = adapter.getcount(); index < len; index++) {

   final view tabview = layoutinflater.from(getcontext()).inflate(mlayoutid, this, false); //加载tab布局
   mtabview[index] = tabview;

   /*tabiconview初始化*/
   tabiconview iconview = null;
   if (miconviewid > 0) { // 传入的图片资源文件id不为0时,表示需要显示icon,然后初始化该view
    iconview = (tabiconview) tabview.findviewbyid(miconviewid);
    iconview.init(miconres[index][0], miconres[index][1], miconwidth, miconheight); //这里调了自定义imageview的init方法
   }

   /*tabtextview初始化*/
   textview textview = null;
   if (mtextviewid > 0) {
    textview = (textview) tabview.findviewbyid(mtextviewid);
    textview.settext(mtitles[index]);

   }

   /*设置宽度,等分container*/
   layoutparams lp = (layoutparams) tabview.getlayoutparams();
   lp.width = 0;
   lp.weight = 1;

   /*添加tab点击事件*/
   addtabonclicklistener(tabview, index);

   /*设置当前状态*/
   if (index == mviewpager.getcurrentitem()) { //当先显示tab,设置初始状态为获得焦点状态
    if (iconview != null) {
     iconview.offsetchanged(0);
    }
    tabview.setselected(true);
    if (textview != null) {
     textview.settextcolor(mtextselectedcolor);
    }
   }

   addview(tabview);
  }
 }

3).监听viewpager的滑动事件,根据偏移值更新container,完成重绘操作

4).在container的ondraw中根据偏移量计算透明值,这里文本偏移值计算用了一个开源的代码

@override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  final int childcount = getchildcount();
  if (childcount > 0) {
   /*当发生偏移时,绘制渐变区域*/
   if (mselectionoffset > 0f && mselectedposition < (getchildcount() - 1) && mshowtransitioncolor) {

    /*获取当前tab和下一tab view */
    view selectedtab = getchildat(mselectedposition);
    view nexttab = getchildat(mselectedposition + 1);

    /*显示tab icon时,刷新各自view 透明度*/
    if (miconviewid > 0) {
     view selectediconview = selectedtab.findviewbyid(miconviewid);
     view nexticonview = nexttab.findviewbyid(miconviewid);

     //draw icon alpha
     if (selectediconview instanceof tabiconview && nexticonview instanceof tabiconview) {
      ((tabiconview) selectediconview).offsetchanged(mselectionoffset);
      ((tabiconview) nexticonview).offsetchanged(1 - mselectionoffset);
     }
    }

     /*显示tab text,刷新各自view 透明度*/
    if (mtextviewid > 0) {
     view selectedtextview = selectedtab.findviewbyid(mtextviewid);
     view nexttextview = nexttab.findviewbyid(mtextviewid);

     //draw text color
     integer selectedcolor = (integer) evaluate(mselectionoffset, mtextselectedcolor, mtextnormalcolor);
     integer nextcolor = (integer) evaluate(1 - mselectionoffset, mtextselectedcolor, mtextnormalcolor);

     if (selectedtextview instanceof textview && nexttextview instanceof textview) {
      ((textview) selectedtextview).settextcolor(selectedcolor);
      ((textview) nexttextview).settextcolor(nextcolor);
     }
    }

   }
  }
 }

3.定义个fragmentadapter,这个就略过,比较简单了 

4.做了以上准备工作,就可以写个测试例子试试效果了,当然这里为了看到效果,我们需要事先准备好几张图片,以及几个fragment 

private void initviews() {  //得到apdater
  tabfragmentadapter madapter = new tabfragmentadapter(getsupportfragmentmanager(), fragments);
  viewpager mpager = (viewpager) findviewbyid(r.id.tab_pager);
  mpager.setadapter(madapter);
  //如果当前类需要对viewpager做监听
  tabcontainerview mtablayout = (tabcontainerview) findviewbyid(r.id.ll_tab_container);
  mtablayout.setonpagechangelistener(this);

  mtablayout.initcontainer(getresources().getstringarray(r.array.tab_main_title), icons_res, tab_colors, true);

  int width = getresources().getdimensionpixelsize(r.dimen.tab_icon_width);
  int height = getresources().getdimensionpixelsize(r.dimen.tab_icon_height);
  mtablayout.setcontainerlayout(r.layout.tab_container_view, r.id.iv_tab_icon, r.id.tv_tab_text, width, height);
//  mtablayout.setsingletextlayout(r.layout.tab_container_view, r.id.tv_tab_text);
//  mtablayout.setsingleiconlayout(r.layout.tab_container_view, r.id.iv_tab_icon);

  mtablayout.setviewpager(mpager);
  mpager.setcurrentitem(getintent().getintextra("tab", 0));
 }

manactivity对应的xml就比较简单了,可以参考源码,最后运行效果,就是上面的贴图了,到此防微信的滑动切换就完成了,源码请访问以下链接: 

源码下载:https://github.com/jarekwang/wechathome.git

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。