Android 仿支付宝城市服务栏目tab选择滑动子View效果
程序员文章站
2022-03-09 21:37:57
一. 图示
支付宝效果
实现的效果
二. 思路讲解
tablayout+scrollview实现即可。每一个tab对应scrollview中包裹的一层布局,以上有4个tab,也就需要inf...
一. 图示
支付宝效果实现的效果
二. 思路讲解
tablayout+scrollview实现即可。每一个tab对应scrollview中包裹的一层布局,以上有4个tab,也就需要inflate 4个布局文件,用来表示每一层的样式内容。
1.页面加载完毕后,记住每一层父布局在screen中所要滑动至顶部的距离distance;
2.操作:
a. 当点击tab时:滑动scrollview该层的距离distance;
b. 当滑动scrollview至对应的层时: 选定对应的tab。
三. 代码
1. 布局代码
<framelayout android:layout_height="wrap_content" android:layout_width="match_parent"> <framelayout android:id="@+id/wrapperfl" android:layout_height="match_parent" android:layout_width="match_parent"></framelayout> </framelayout>
布局代码很简单,可能会有的疑问点有:
a. wrapperfl是用来干啥的?
b. observablescrollview又是个什么东西?
(后面说明)
2. 逻辑代码
public class mainactivity extends appcompatactivity implements observablescrollview.scrollviewlistener { private static final string tag = "mainactivity"; private framelayout wrapperfl; private tablayout tablayout; private observablescrollview scrollview; private linearlayout containerll; private boolean firstalreadyinflated = true; private viewgroup firstfloorvg; private viewgroup secondfloorvg; private viewgroup thirdfloorvg; private viewgroup fourthfloorvg; private int secondfloorvgpositiondistance;//第二层滑动至顶部的距离 private int thirdfloorvgpositiondistance; private int fourthfloorvgpositiondistance; private int currentposition = 0; private boolean tabintercepttoucheventtag = true;//标志位,用来区分是点击了tab还是手动滑动scrollview @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); initviews(); initlisteners(); } private void initviews() { wrapperfl = (framelayout) findviewbyid(r.id.wrapperfl); tablayout = (tablayout) findviewbyid(r.id.tablayout); scrollview = (observablescrollview) findviewbyid(r.id.scrollview); containerll = (linearlayout) findviewbyid(r.id.containerll); for (int i = 0; i < 4; i++) { tablayout.addtab(tablayout.newtab().settext("tab" + (i + 1))); } firstfloorvg = (viewgroup) layoutinflater.from(this).inflate(r.layout.item_floor_first, null); secondfloorvg = (viewgroup) layoutinflater.from(this).inflate(r.layout.item_floor_second, null); thirdfloorvg = (viewgroup) layoutinflater.from(this).inflate(r.layout.item_floor_third, null); fourthfloorvg = (viewgroup) layoutinflater.from(this).inflate(r.layout.item_floor_fourth, null); containerll.addview(firstfloorvg); containerll.addview(secondfloorvg); containerll.addview(thirdfloorvg); containerll.addview(fourthfloorvg); } @override public void onwindowfocuschanged(boolean hasfocus) { super.onwindowfocuschanged(hasfocus); if (firstalreadyinflated) {//获取各层离screen顶部的位置以及计算滑动值相应顶部所需要的距离 firstalreadyinflated = false; int[] firstfloorvgposition = new int[2]; int[] secondfloorvgposition = new int[2]; int[] thirdfloorvgposition = new int[2]; int[] fourthfloorvgposition = new int[2]; firstfloorvg.getlocationonscreen(firstfloorvgposition); secondfloorvg.getlocationonscreen(secondfloorvgposition); thirdfloorvg.getlocationonscreen(thirdfloorvgposition); fourthfloorvg.getlocationonscreen(fourthfloorvgposition); int firstfloorvgpositionanchor = firstfloorvgposition[1]; int secondfloorvgpositionanchor = secondfloorvgposition[1]; int thirdfloorvgpositionanchor = thirdfloorvgposition[1]; int fourthfloorvgpositionanchor = fourthfloorvgposition[1]; log.d(tag, "第一层距离屏幕的距离是:" + firstfloorvgposition[1]); log.d(tag, "第二层距离屏幕的距离是:" + secondfloorvgposition[1]); log.d(tag, "第三层距离屏幕的距离是:" + thirdfloorvgposition[1]); log.d(tag, "第四层距离屏幕的距离是:" + fourthfloorvgposition[1]); secondfloorvgpositiondistance = secondfloorvgpositionanchor - firstfloorvgpositionanchor; thirdfloorvgpositiondistance = thirdfloorvgpositionanchor - firstfloorvgpositionanchor; fourthfloorvgpositiondistance = fourthfloorvgpositionanchor - firstfloorvgpositionanchor; } } private void initlisteners() { wrapperfl.setontouchlistener(new view.ontouchlistener() { @override public boolean ontouch(view v, motionevent event) { log.d(tag,"wrapperfl ontouch"); tabintercepttoucheventtag = true;//让tab来处理滑动 return false; } }); tablayout.addontabselectedlistener(new tablayout.ontabselectedlistener() { @override public void ontabselected(tablayout.tab tab) { currentposition = tab.getposition(); if(!tabintercepttoucheventtag){//手动滑动页面时则不再次处理滑动 return; } scrollview.computescroll(); switch (currentposition) { case 0: scrollview.smoothscrollto(0, 0); break; case 1: scrollview.smoothscrollto(0, secondfloorvgpositiondistance); break; case 2: scrollview.smoothscrollto(0, thirdfloorvgpositiondistance); break; case 3: scrollview.smoothscrollto(0, fourthfloorvgpositiondistance); break; default: break; } } @override public void ontabunselected(tablayout.tab tab) { } @override public void ontabreselected(tablayout.tab tab) { } }); scrollview.setscrollviewlistener(this); scrollview.setontouchlistener(new view.ontouchlistener() { @override public boolean ontouch(view v, motionevent event) { log.d(tag, "scrollview ontouch"); tabintercepttoucheventtag = false;//让scrollview处理滑动 return false; } }); } @override public void onscrollchanged(observablescrollview scrollview, int x, int y, int oldx, int oldy) { if (tabintercepttoucheventtag) {//让tab来处理滑动 return; } log.d(tag, "当前scrollview的位置——>" + y); if (y < secondfloorvgpositiondistance) { if (currentposition != 0) { scrollview.computescroll(); tablayout.gettabat(0).select(); } } else if (y < thirdfloorvgpositiondistance) { if (currentposition != 1) { scrollview.computescroll(); tablayout.gettabat(1).select(); } } else if (y < fourthfloorvgpositiondistance) { if (currentposition != 2) { scrollview.computescroll(); tablayout.gettabat(2).select(); } } else { if (currentposition != 3) { scrollview.computescroll(); tablayout.gettabat(3).select(); } } } }
a. tabintercepttoucheventtag 作为标志位是为了防止因scrollview触发了tab selected从而再次引起scrollview滑动导致的滑动不流畅。
b. wrapperfl的存在则是要去给 tabintercepttoucheventtag 赋值,因为tablayout的touch、click、focus等事件被消化掉了,无法在这些事件中监听到对应的值的变化,所以通过wrapperfl来进行touch事件的监听。
c. observablescrollview 是继承自scrollview,新增和改变了其中的以下方法:
public void setscrollviewlistener(scrollviewlistener scrollviewlistener) { this.scrollviewlistener = scrollviewlistener; } @override protected void onscrollchanged(int x, int y, int oldx, int oldy) { super.onscrollchanged(x, y, oldx, oldy); if (scrollviewlistener != null) { scrollviewlistener.onscrollchanged(this, x, y, oldx, oldy); } } public interface scrollviewlistener { void onscrollchanged(observablescrollview scrollview, int x, int y, int oldx, int oldy); }
这样就可以在activity主界面中监听到scrollview的滑动事件,从而获取当前整个scrollview所处的位置,进而去判定是否需要选定对应的tab。