当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现微信首页左右滑动切换效果

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

绍兴租房网,night社的邪恶校草们,延安整风运动的方针

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

之前也在博客上看到别人的实现,再次基础上,我做了些优化。首先说下实现原理,大神略过,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

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网