Android Behavior之ViewPager+Fragment+RecyclerView實(shí)現(xiàn)吸頂效果

前言

做了一個(gè)月的前端開(kāi)發(fā) 逐漸學(xué)習(xí)vue3+ts開(kāi)發(fā) 已經(jīng)可以正常寫(xiě)功能 只是有些原理還沒(méi)有搞懂!
說(shuō)起來(lái) 只要自己想學(xué)習(xí),其實(shí)也沒(méi)有那么難。畢竟TypeScript跟java太像了!
語(yǔ)法很像,都是面向?qū)ο笏枷耄?/p>

Android

由于項(xiàng)目緊急任務(wù) 需要在2個(gè)星期內(nèi)做一個(gè)平板端的操作app
領(lǐng)導(dǎo)又安排我回到了android崗位,話說(shuō)開(kāi)發(fā)是公司的一塊磚 哪里需要哪里搬 深有體會(huì)
兩個(gè)星期開(kāi)發(fā)一個(gè)app,時(shí)間上還是很趕的,由于和另外一個(gè)同事一起開(kāi)發(fā),壓力也沒(méi)那么大

三軍未動(dòng),糧草先行

雖然接口還沒(méi)有出來(lái),但UI已出,可以先工作了,不需要太大腦力勞動(dòng)的畫(huà)頁(yè)面操作,是每個(gè)android以及每個(gè)前端開(kāi)發(fā)工程師的基礎(chǔ)必備技能!
在和UI探討后,得到一個(gè)吸頂效果的需求,大概就是導(dǎo)航欄可以隨著滑動(dòng)改變位置。
這樣的需求也做過(guò)很多,2018年前后比較流行----------behavior
以前看過(guò)很多技術(shù)類(lèi)的博客 但是自己沒(méi)有記錄過(guò),雖然已經(jīng)是很舊的知識(shí)點(diǎn)了,這里再?gòu)?fù)習(xí)一下

Test效果圖

吸頂效果test.gif

實(shí)現(xiàn)思路

其實(shí)不需要代碼輔助就可以完成上述的效果 這里指的是邏輯層的代碼
我們只需要再XML文件,完成合理的布局已經(jīng)屬性聲明 即可完成上述的效果

我這里運(yùn)用了 CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+TabLayout+ViewPager
這一套組合

Coordinator在英文中是協(xié)調(diào)的意思,所以我把CoordinatorLayout叫做協(xié)調(diào)者布局

AppBarLayout的直接子控件可以設(shè)置的屬性:layout_scrollFlags:

1.scroll|exitUntilCollapsed如果AppBarLayout的直接子控件設(shè)置該屬性,該子控件可以滾動(dòng),向上滾動(dòng)NestedScrollView出父布局(一般為CoordinatorLayout)時(shí),會(huì)折疊到頂端,向下滾動(dòng)時(shí)NestedScrollView必須滾動(dòng)到最上面的時(shí)候才能拉出該布局
2.scroll|enterAlways:只要向下滾動(dòng)該布局就會(huì)顯示出來(lái),只要向上滑動(dòng)該布局就會(huì)向上收縮
3.scroll|enterAlwaysCollapsed:向下滾動(dòng)NestedScrollView到最底端時(shí)該布局才會(huì)顯示出來(lái)
4.如果不設(shè)置改屬性,則改布局不能滑動(dòng)

CollapsingToolbarLayout:折疊的toolbar,它確實(shí)是起到折疊作用的,可以把自己的自布局折疊.
它的直接子布局可以使用的屬性:app:layout_collapseMode(折疊模式):可取的值如下:
1.pin:在滑動(dòng)過(guò)程中,此自布局會(huì)固定在它所在的位置不動(dòng),直到CollapsingToolbarLayout全部折疊或者全部展開(kāi)
2.parallax:視察效果,在滑動(dòng)過(guò)程中,不管上滑還是下滑都會(huì)有視察效果,不知道什么事視察效果自己看gif圖(layout_collapseParallaxMultiplier視差因子 0~1之間取值,當(dāng)設(shè)置了parallax時(shí)可以配合這個(gè)屬性使用,調(diào)節(jié)自己想要的視差效果)
3.不設(shè)置:跟隨NestedScrollView的滑動(dòng)一起滑動(dòng),NestedScrollView滑動(dòng)多少距離他就會(huì)跟著走多少距離

TabLayout 是一個(gè)選項(xiàng)卡布局 一般和ViewPager配合使用 一遍達(dá)到聯(lián)動(dòng)的效果 跟著滑動(dòng)
ViewPager 視圖滑動(dòng)切換組件 和TabLayout組合可以達(dá)到兩者聯(lián)動(dòng)效果 當(dāng)然自己也可以獨(dú)立使用
上面這2個(gè)都是android應(yīng)用開(kāi)發(fā)經(jīng)常用到的組件

XML代碼布局

仔細(xì)觀察下面xml布局,用到了2個(gè)關(guān)鍵屬性

第一個(gè)屬性 layout_scrollFlags

CollapsingToolbarLayout的
app:layout_scrollFlags="exitUntilCollapsed|scroll"
當(dāng)ScrollView將要向下滾動(dòng)的時(shí)候,優(yōu)先滾動(dòng)的是自己,當(dāng)自己滾動(dòng)到頂部頭的時(shí)候,再開(kāi)始觸發(fā)滾動(dòng)
1:AppBarLayoout中的childView;
這和單純使用scroll的效果是一致的;
2:當(dāng)Scrollview將要向上滾動(dòng)的時(shí)候,優(yōu)先將AppBarLayout中的childView滾動(dòng)至最小高度,然后scrollview才開(kāi)始滾動(dòng)。

第二個(gè)屬性 layout_behavior

app:layout_behavior="@string/appbar_scrolling_view_behavior"
android 系統(tǒng)層的滾動(dòng)屬性,沒(méi)有設(shè)置的話, AppbarLayout將不會(huì)響應(yīng)滾動(dòng)布局的滾動(dòng)事件.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/coll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#2196F3"
            android:fitsSystemWindows="true"
            app:layout_scrollFlags="exitUntilCollapsed|scroll">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@drawable/ic_launcher_background" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容1"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容2"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容3"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容4"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容5"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容6"
                    android:textColor="#fff"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:padding="20dp"
                    android:text="我是內(nèi)容7"
                    android:textColor="#fff"
                    android:textSize="20sp" />
            </LinearLayout>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tablayout"
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:background="#FFF"
            app:tabIndicatorColor="@android:color/holo_blue_dark"
            app:tabSelectedTextColor="@color/purple_200"
            app:tabTextColor="#000" />


    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />


</androidx.coordinatorlayout.widget.CoordinatorLayout>

數(shù)據(jù)層代碼

Activity

public class MainActivity extends AppCompatActivity {


    private final List<Fragment> list = new ArrayList<>();
    private final List<String> title = new ArrayList<>();
    CollapsingToolbarLayout collapsingToolbarLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TabLayout tabLayout = findViewById(R.id.tablayout);
        ViewPager viewPager = findViewById(R.id.viewpager);
        collapsingToolbarLayout = findViewById(R.id.coll);


        title.add("Tab1");
        title.add("Tab2");

        OneFragment oneFragment = new OneFragment();
        TwoFragment twoFragment = new TwoFragment();
        list.add(oneFragment);
        list.add(twoFragment);

        collapsingToolbarLayout.setTitle("我是返回");

        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @NonNull
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }

            @Override
            public int getCount() {
                return list.size();
            }

            @Nullable
            @Override
            public CharSequence getPageTitle(int position) {
                return title.get(position);
            }
        });

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset,
             int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        tabLayout.setupWithViewPager(viewPager);
        tabLayout.setTabMode(TabLayout.MODE_FIXED);
    }
}

Fragment

public class OneFragment extends Fragment {
    private final List<String> stringList = new ArrayList<>();

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, 
    @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //數(shù)據(jù)
        initString();

        RecyclerView recyclerView = view.findViewById(R.id.recyclerview);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        TextAdapter adapter = new TextAdapter(stringList);
        recyclerView.setAdapter(adapter);
    }

    private void initString() {
        for (int i = 0; i < 20; i++) {
            stringList.add("0");
            stringList.add("1");
            stringList.add("2");
            stringList.add("3");
            stringList.add("4");
        }

    }
}

Adapter

public class TextAdapter extends RecyclerView.Adapter<TextAdapter.ViewHolder> {
    private final List<String> stringList;

    public TextAdapter(List<String> list) {
        stringList = list;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        Button mButton;
        public static int anInt = 0;

        public ViewHolder(View view) {
            super(view);
            mButton = view.findViewById(R.id.item_btn);
            anInt++;
        }
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text_type, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        //綁定子view事件
        holder.mButton.setText(String.format("我是Item %s",position));
    }


    @Override
    public int getItemCount() {
        return stringList.size();
    }

    @Override
    public int getItemViewType(int position) {
        return -1;
    }

}

布局就不貼了 一個(gè)是recyclerView 一個(gè)是Item

效果圖

另外附一張項(xiàng)目中的效果圖 實(shí)現(xiàn)原理差不多

吸頂效果project.gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容