Android实现微信首页左右滑动切换效果
大家看到微信首页切换效果有没有觉得很炫,滑动切换,点击底部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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。