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

Android 仿支付宝城市服务栏目tab选择滑动子View效果

程序员文章站 2022-06-23 16:26:58
一. 图示 支付宝效果 实现的效果 二. 思路讲解 tablayout+scrollview实现即可。每一个tab对应scrollview中包裹的一层布局,以上有4个tab,也就需要inf...

一. 图示

Android 仿支付宝城市服务栏目tab选择滑动子View效果 支付宝效果
Android 仿支付宝城市服务栏目tab选择滑动子View效果实现的效果

二. 思路讲解

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