最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Android開(kāi)發(fā)學(xué)習(xí)教程(27)- ViewPager+Fragment+FragmentPagerAdapter+Fragm

2023-01-29 22:57 作者:ChatGPT云炬學(xué)長(zhǎng)  | 我要投稿

—— 我從未見(jiàn)過(guò)一個(gè)早起勤奮謹(jǐn)慎誠(chéng)實(shí)的人抱怨命運(yùn)不好,良好的品格,堅(jiān)強(qiáng)的意志,是不會(huì)被所謂的命運(yùn)擊敗的。

ViewPager是什么

ViewPager是一個(gè)布局管理器,用戶通過(guò)左右移動(dòng)來(lái)滑動(dòng)頁(yè)面,其中每個(gè)頁(yè)面使用Fragment而不是使用Activity。它還可以用在用戶首次啟動(dòng)應(yīng)用程序時(shí)的引導(dǎo)頁(yè)。

ViewPager的用法

實(shí)現(xiàn)viewpager的步驟:

1. 將 ViewPager 小部件添加到 XML 布局中。

2. 通過(guò)擴(kuò)展 FragmentPagerAdapter 或 FragmentStatePagerAdapter 類(lèi)來(lái)創(chuàng)建適配器。

適配器用來(lái)填充 Viewpager 內(nèi)的頁(yè)面。PagerAdapter 是由 FragmentPagerAdapter 和 FragmentStatePagerAdapter 擴(kuò)展的基類(lèi),讓我們看一下這兩個(gè)類(lèi)之間的區(qū)別。

FragmentPagerAdapter 和 FragmentStatePagerAdapter 的區(qū)別:

(1)fragments對(duì)象的處理:FragmentPagerAdapter范圍外fragments會(huì)保存在內(nèi)存中(detach),但是fragment對(duì)應(yīng)的View會(huì)被銷(xiāo)毀;FragmentStatePagerAdapter范圍外fragments不會(huì)保存在內(nèi)存中(remove),View也會(huì)被銷(xiāo)毀。

(2)狀態(tài)的處理:FragmentPagerAdapter范圍外fragments對(duì)應(yīng)的SavedState會(huì)保存;FragmentStatePagerAdapter只保存范圍內(nèi)fragments對(duì)應(yīng)的SavedState。這個(gè)SavedState在Fragment的生命周期回調(diào)中供外部傳參數(shù),和Activity類(lèi)似。

(3)適用場(chǎng)景:相同數(shù)量的fragments,F(xiàn)ragmentPagerAdapter內(nèi)存較大,但頁(yè)面切換更友好;FragmentStatePagerAdapter內(nèi)存占用少,頁(yè)面切換稍差。因此FragmentPagerAdapter適用于Fragment數(shù)量少的情況,F(xiàn)ragmentStatePagerAdapter適用于Fragment數(shù)量多的情況。

FragmentPagerAdapter的用法

第 1 步:將 ViewPager 小部件添加到 XML 布局中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml?version="1.0"?encoding="utf-8"?>
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"
????xmlns:app="http://schemas.android.com/apk/res-auto"
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:orientation="vertical">
????<com.google.android.material.tabs.TabLayout
????????android:id="@+id/tab_layout"
????????android:layout_width="match_parent"
????????android:layout_height="wrap_content"
????????app:tabGravity="fill"
????????app:tabMode="fixed"?/>
????<androidx.viewpager.widget.ViewPager
????????android:id="@+id/viewpager"
????????android:layout_width="match_parent"
????????android:layout_height="match_parent"?/>
</LinearLayout>

第 2 步:創(chuàng)建Fragment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import?android.os.Bundle;
import?android.view.LayoutInflater;
import?android.view.View;
import?android.view.ViewGroup;
import?androidx.annotation.NonNull;
import?androidx.annotation.Nullable;
import?androidx.fragment.app.Fragment;
public?class?Page1Fragment?extends?Fragment {
????public?Page1Fragment() {
????????// required empty public constructor.
????}
????@Override
????public?void?onCreate(@Nullable?Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????}
????@Nullable
????@Override
????public?View onCreateView(@NonNull?LayoutInflater inflater,?@Nullable?ViewGroup container,?@Nullable?Bundle savedInstanceState) {
????????return?inflater.inflate(R.layout.fragment_page1, container,?false);
????}
}

fragment_page1.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml?version="1.0"?encoding="utf-8"?>
<FrameLayout
????xmlns:android="http://schemas.android.com/apk/res/android"
????xmlns:tools="http://schemas.android.com/tools"
????android:layout_width="match_parent"
????android:layout_height="match_parent"
????android:background="#0F9D58"
????tools:context=".Page1Fragment">

????

????<!-- TODO: Update blank fragment layout -->
????<TextView
????????android:layout_width="match_parent"
????????android:layout_height="match_parent"
????????android:gravity="center"
????????android:text="Page 1"
????????android:textColor="@color/white"
????????android:textSize="60sp"
????????android:textStyle="bold"?/>
</FrameLayout>

和上面一樣再分別新建Page2Fragment、fragment_page2.xml、Page3Fragment、fragment_page3.xml

第 3 步:創(chuàng)建 ViewPager 適配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
??import?androidx.annotation.NonNull;
??import?androidx.annotation.Nullable;
??import?androidx.fragment.app.Fragment;
??import?androidx.fragment.app.FragmentManager;
??import?androidx.fragment.app.FragmentPagerAdapter;
??import?java.util.ArrayList;
??import?java.util.List;
??public?class?ViewPagerAdapter?extends?FragmentPagerAdapter {
??????private?final?List<fragment> fragments =?new?ArrayList<>();
??????private?final?List<string> fragmentTitle =?new?ArrayList<>();
??????public?ViewPagerAdapter(@NonNull?FragmentManager fm)
??????{
??????????super(fm);
??????}
??????public?void?add(Fragment fragment, String title)
??????{
??????????fragments.add(fragment);
??????????fragmentTitle.add(title);
??????}
??????@NonNull?@Override?public?Fragment getItem(int?position)
??????{
??????????return?fragments.get(position);
??????}
??????@Override?public?int?getCount()
??????{
??????????return?fragments.size();
??????}
??????@Nullable
??????@Override
??????public?CharSequence getPageTitle(int?position)
??????{
??????????return?fragmentTitle.get(position);
??????}
??}
</string></fragment>

方法說(shuō)明:

1
2
3
4
5
6
getCount():此方法返回要顯示的片段數(shù)。(需要覆蓋)
getItem(int?pos):返回 pos 索引處的片段。(需要覆蓋)
ViewPagerAdapter(@NonNull?FragmentManager FM):(必需)ViewPager Adapter 需要有一個(gè)接受 FragmentManager 實(shí)例的參數(shù)化構(gòu)造函數(shù)。它負(fù)責(zé)管理片段。FragmentManager 管理 Android 中的 Fragment,具體來(lái)說(shuō),它處理 Fragment 之間的事務(wù)。事務(wù)是一種添加、替換或刪除片段的方法。
getPageTitle(int?pos):(可選)與 getItem() 類(lèi)似,此方法返回索引 pos 處的頁(yè)面標(biāo)題。
add(Fragment fragment, String title):此方法負(fù)責(zé)填充片段和片段標(biāo)題列表。分別持有片段和標(biāo)題。

第 4 步:ViewPager設(shè)置適配器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import?android.os.Bundle;
import?androidx.appcompat.app.AppCompatActivity;
import?androidx.viewpager.widget.ViewPager;
import?com.google.android.material.tabs.TabLayout;
public?class?MainActivity?extends?AppCompatActivity {

????

????private?ViewPagerAdapter viewPagerAdapter;
????private?ViewPager viewPager;
????private?TabLayout tabLayout;

????

????@Override
????protected?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main);
????????viewPager = findViewById(R.id.viewpager);
????????// 實(shí)例化適配器
????????viewPagerAdapter =?new?ViewPagerAdapter(getSupportFragmentManager());
????????viewPagerAdapter.add(new?Page1Fragment(),?"Page 1");
????????viewPagerAdapter.add(new?Page2Fragment(),?"Page 2");
????????viewPagerAdapter.add(new?Page3Fragment(),?"Page 3");
????????// viewPager設(shè)置適配器
????????viewPager.setAdapter(viewPagerAdapter);
????????tabLayout = findViewById(R.id.tab_layout);
????????// 使用setupWithiewPager方法將 TabLayout 鏈接到 Viewpager
????????tabLayout.setupWithViewPager(viewPager);
????}
}


FragmentStatePagerAdapter的用法

其它步驟和上面一樣,這里Fragment我們使用同一個(gè),只是針對(duì)不同的tab設(shè)置不同的內(nèi)容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import?android.os.Bundle;
import?android.view.LayoutInflater;
import?android.view.View;
import?android.view.ViewGroup;
import?android.widget.TextView;
import?androidx.annotation.NonNull;
import?androidx.annotation.Nullable;
import?androidx.fragment.app.Fragment;
public?class?DynamicFragment?extends?Fragment {
????public?static?DynamicFragment newInstance(String arg) {
????????Bundle bundle =?new?Bundle();
????????bundle.putString("arg", arg);
????????DynamicFragment fragment =?new?DynamicFragment();
????????fragment.setArguments(bundle);
????????return?fragment;
????}
????@Nullable
????@Override
????public?View onCreateView(@NonNull?LayoutInflater inflater,?@Nullable?ViewGroup container,?@Nullable?Bundle savedInstanceState) {
????????return?inflater.inflate(R.layout.fragment_page, container,?false);
????}
????@Override
????public?void?onViewCreated(@NonNull?View view,?@Nullable?Bundle savedInstanceState) {
????????super.onViewCreated(view, savedInstanceState);
????????((TextView) getView().findViewById(R.id.tv)).setText("Page"?+ getArguments().getString("arg"));
????}
}

適配器部分和上面的ViewPagerAdapter內(nèi)容一樣,區(qū)別只是繼承的是 FragmentStatePagerAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
??import?java.util.ArrayList;
??import?java.util.List;
??import?androidx.annotation.Nullable;
??import?androidx.fragment.app.Fragment;
??import?androidx.fragment.app.FragmentManager;
??import?androidx.fragment.app.FragmentStatePagerAdapter;
??public?class?DynamicFragmentAdapter?extends?FragmentStatePagerAdapter {
??????private?final?List<fragment> fragments =?new?ArrayList<>();
??????private?final?List<string> fragmentTitle =?new?ArrayList<>();
??????public?DynamicFragmentAdapter(FragmentManager fm) {
??????????super(fm);
??????}
??????public?void?add(Fragment fragment, String title) {
??????????fragments.add(fragment);
??????????fragmentTitle.add(title);
??????}
??????// get the current item with position number
??????@Override
??????public?Fragment getItem(int?position) {
??????????return?fragments.get(position);
??????}
??????// get total number of tabs
??????@Override
??????public?int?getCount() {
??????????return?fragmentTitle.size();
??????}
??????@Nullable
??????@Override
??????public?CharSequence getPageTitle(int?position) {
??????????return?fragmentTitle.get(position);
??????}
??}
</string></fragment>

MainActivity也只是實(shí)例化適配器時(shí)改變了下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public?class?MainActivity2?extends?AppCompatActivity {
????private?DynamicFragmentAdapter dynamicFragmentAdapter;
????private?ViewPager viewPager;
????private?TabLayout tabLayout;
????@Override
????protected?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main1);
????????viewPager = findViewById(R.id.viewpager);
????????// 實(shí)例化適配器
????????dynamicFragmentAdapter =?new?DynamicFragmentAdapter(getSupportFragmentManager());
????????dynamicFragmentAdapter.add(DynamicFragment.newInstance("1"),?"PAGE 1");
????????dynamicFragmentAdapter.add(DynamicFragment.newInstance("2"),?"PAGE 2");
????????dynamicFragmentAdapter.add(DynamicFragment.newInstance("3"),?"PAGE 3");
????????// viewPager設(shè)置適配器
????????viewPager.setAdapter(dynamicFragmentAdapter);
????????tabLayout = findViewById(R.id.tab_layout);
????????// 使用setupWithiewPager方法將 TabLayout 鏈接到 Viewpager
????????tabLayout.setupWithViewPager(viewPager);
????}
}

FragmentPagerAdapter和FragmentStatePagerAdapter不同的根本原因

任何不同的根本原因都可以從源碼中找到,我們來(lái)看下從源碼的角度兩者有何不同

Ctrl+鼠標(biāo)點(diǎn)擊跳轉(zhuǎn)到源碼內(nèi)部,我們發(fā)現(xiàn),兩者都是繼承自PagerAdapter,整體代碼非常簡(jiǎn)短,只有200行,里面有兩個(gè)方法instantiateItem和destroyItem

FragmentPagerAdapter instantiateItem方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@NonNull
@Override
public?Object instantiateItem(@NonNull?ViewGroup container,?int?position) {
????if?(mCurTransaction ==?null) {
????????mCurTransaction = mFragmentManager.beginTransaction();
????}
????final?long?itemId = getItemId(position);
????// Do we already have this fragment?
????String name = makeFragmentName(container.getId(), itemId);
????Fragment fragment = mFragmentManager.findFragmentByTag(name);
????if?(fragment !=?null) {
????????if?(DEBUG) Log.v(TAG,?"Attaching item #"?+ itemId +?": f="?+ fragment);
????????mCurTransaction.attach(fragment);
????}?else?{
????????fragment = getItem(position);
????????if?(DEBUG) Log.v(TAG,?"Adding item #"?+ itemId +?": f="?+ fragment);
????????mCurTransaction.add(container.getId(), fragment,
????????????????makeFragmentName(container.getId(), itemId));
????}
????if?(fragment != mCurrentPrimaryItem) {
????????fragment.setMenuVisibility(false);
????????fragment.setUserVisibleHint(false);
????}
????return?fragment;
}

此方法用來(lái)為每一個(gè)頁(yè)面創(chuàng)建頁(yè)面(這里也就是Fragment了),源碼其實(shí)很簡(jiǎn)單,先獲取FragmentManager事務(wù)對(duì)象,然后用findFragmentByTag查找Fragment,找到了就attach上去,沒(méi)找到就調(diào)用getItem方法獲取定義的Fragment然后add上去。

FragmentStatePagerAdapter instantiateItem方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@NonNull
@Override
public?Object instantiateItem(@NonNull?ViewGroup container,?int?position) {
????// If we already have this item instantiated, there is nothing
????// to do.? This can happen when we are restoring the entire pager
????// from its saved state, where the fragment manager has already
????// taken care of restoring the fragments we previously had instantiated.
????if?(mFragments.size() > position) {
????????Fragment f = mFragments.get(position);
????????if?(f !=?null) {
????????????return?f;
????????}
????}
????if?(mCurTransaction ==?null) {
????????mCurTransaction = mFragmentManager.beginTransaction();
????}
????Fragment fragment = getItem(position);
????if?(DEBUG) Log.v(TAG,?"Adding item #"?+ position +?": f="?+ fragment);
????if?(mSavedState.size() > position) {
????????Fragment.SavedState fss = mSavedState.get(position);
????????if?(fss !=?null) {
????????????fragment.setInitialSavedState(fss);
????????}
????}
????while?(mFragments.size() <= position) {
????????mFragments.add(null);
????}
????fragment.setMenuVisibility(false);
????fragment.setUserVisibleHint(false);
????mFragments.set(position, fragment);
????mCurTransaction.add(container.getId(), fragment);
????return?fragment;
}

此方法一樣用來(lái)為每一個(gè)頁(yè)面創(chuàng)建頁(yè)面,源碼同樣也很簡(jiǎn)單,先在mFragments集合中查找有無(wú)對(duì)應(yīng)頁(yè)面的Fragmet,剛開(kāi)始mFragments肯定是0,繼續(xù)就往下執(zhí)行,獲取FragmentManager事務(wù)對(duì)象,然后用調(diào)用getItem方法獲取定義的Fragment然后add上去。

到這里,首先就有個(gè)很明顯的區(qū)別,上面需要先經(jīng)過(guò)findFragmentByTag而這里是直接從mFragments查找有無(wú)對(duì)應(yīng)頁(yè)面的Fragmet,效率肯定快多了吧,至于為什么這里可以直接從mFragments查找,繼續(xù)往下看

FragmentPagerAdapter destroyItem方法:

1
2
3
4
5
6
7
8
9
10
@Override
public?void?destroyItem(@NonNull?ViewGroup container,?int?position,?@NonNull?Object object) {
????if?(mCurTransaction ==?null) {
????????mCurTransaction = mFragmentManager.beginTransaction();
????}
????if?(DEBUG) Log.v(TAG,?"Detaching item #"?+ getItemId(position) +?": f="?+ object
????????????+?" v="?+ ((Fragment)object).getView());
????mCurTransaction.detach((Fragment)object);
}

很簡(jiǎn)單,就是detach掉某個(gè)Fragment頁(yè)面

FragmentStatePagerAdapter destroyItem方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public?void?destroyItem(@NonNull?ViewGroup container,?int?position,?@NonNull?Object object) {
????Fragment fragment = (Fragment) object;
????if?(mCurTransaction ==?null) {
????????mCurTransaction = mFragmentManager.beginTransaction();
????}
????if?(DEBUG) Log.v(TAG,?"Removing item #"?+ position +?": f="?+ object
????????????+?" v="?+ ((Fragment)object).getView());
????while?(mSavedState.size() <= position) {
????????mSavedState.add(null);
????}
????mSavedState.set(position, fragment.isAdded()
????????????? mFragmentManager.saveFragmentInstanceState(fragment) :?null);
????mFragments.set(position,?null);
????mCurTransaction.remove(fragment);
}

這里是將mFragments對(duì)應(yīng)位置設(shè)為NULL,而且從FragmentManager中remove掉Fragment。這里也解釋了上面為什么可以直接從mFragments查找而不必再使用findFragmentByTag去查找Fragment了,因?yàn)檫@里將mFragments對(duì)應(yīng)位置設(shè)為NULL了。另一方面,這里直接從FragmentManager中remove掉Fragment了,所以FragmentManager在當(dāng)前內(nèi)存中不會(huì)緩存3個(gè)以上的Fragment(假設(shè)讀者使用默認(rèn)的mOffscreenPageLimit),這也是為什么FragmentStatePagerAdapter適用于頁(yè)面數(shù)量多的情形了。

源碼鏈接:https://yunjunet.cn/876823.html

Android開(kāi)發(fā)學(xué)習(xí)教程(27)- ViewPager+Fragment+FragmentPagerAdapter+Fragm的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
通化县| 宜章县| 汨罗市| 淄博市| 福贡县| 盖州市| 迭部县| 长沙县| 庆元县| 香港| 垦利县| 小金县| 大关县| 葫芦岛市| 体育| 烟台市| 津市市| 怀来县| 新竹县| 四平市| 务川| 兴安盟| 桦川县| 安化县| 高尔夫| 邯郸市| 通榆县| 库车县| 屯门区| 军事| 锡林浩特市| 格尔木市| 彭州市| 林口县| 碌曲县| 南平市| 大邑县| 突泉县| 潞城市| 仙桃市| 鲁甸县|