Android TabLayout系列之簡單使用

1 前言

在上一篇 Android TabLayout系列之屬性 中我們介紹了TabLayout的屬性,同時也給出了一些簡單的效果圖。但是沒有具體到它的使用整吆,今天就來看看TabLayout的簡單使用东臀。不知道大家留意到我們仿網(wǎng)易的效果布局中,我們明明是寫的小寫字母隆檀,字母就變成大寫了,還有字體大小能改變否粹湃?我們一步一步來解決這些問題......

2 使用

介紹一種在實際開發(fā)中TabLayout較為常用的方式恐仑,那就是和ViewPager配合使用,實現(xiàn)聯(lián)動为鳄。首先看看xml布局:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabBackground="@android:color/white"
        app:tabIndicatorColor="@android:color/holo_red_light"
        app:tabIndicatorHeight="2dp"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@android:color/holo_red_light"
        app:tabTextColor="@android:color/darker_gray"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

是不是很簡單的布局裳仆,就只有一個TabLayout和ViewPager垂直排列,其實這個還不是官方的布局樣式孤钦,官方的是這樣的:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabBackground="@android:color/white"
            app:tabIndicatorColor="@android:color/holo_red_light"
            app:tabIndicatorHeight="2dp"
            app:tabMode="scrollable"
            app:tabSelectedTextColor="@android:color/holo_red_light"
            app:tabTextColor="@android:color/darker_gray"/>

    <android.support.v4.view.ViewPager/>
</LinearLayout>

第一種是我們常見到的歧斟,第二種是官方的,兩種的區(qū)別是官方這種寫法不用調(diào)用setupWithViewPager方法偏形。接下來我們看看Activity的代碼怎么實現(xiàn)的:

public class MainActivity extends BaseActivity {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;
    private MainPagerAdapter mAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusTracker.init(getApplication());
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void initContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initView() {
        mTabLayout = findView(tabLayout);
        mViewPager = findView(R.id.viewPager);
        for (int i = 0; i < 11; i++) {
            //為TabLayout添加10個tab并設(shè)置上文本
            mTabLayout.addTab(mTabLayout.newTab().setText("Tab " + i));
        }

        mAdapter = new MainPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        //官方推薦的綁定ViewPager方式
        mTabLayout.setupWithViewPager(mViewPager);
    }

    @Override
    protected void initData(@Nullable Bundle savedInstanceState) {

    }

    //ViewPager適配器  10個Fragment
    private class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return BlankFragment.newInstance(position);
        }

        @Override
        public int getCount() {
            return 10;
        }
    }
}

接下來是BlankFragment的實現(xiàn):

public class BlankFragment extends Fragment {
    private int index;

    public BlankFragment() {
        // Required empty public constructor
    }

    public static Fragment newInstance(int position) {
        BlankFragment fragment = new BlankFragment();
        fragment.index = position;
        return fragment;
    }

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

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ((TextView) view.findViewById(R.id.textView)).setText("this Tab " + index);
    }
}

這里需要先解釋newTab静袖,這個newTab是使用TabLayout中默認(rèn)的Tab實現(xiàn)。從它的實現(xiàn)可以看到它支持設(shè)置圖標(biāo)俊扭,標(biāo)題和內(nèi)容描述(圖標(biāo)描述)队橙。

    public static final class Tab {

        /**
         * An invalid position for a tab.
         *
         * @see #getPosition()
         */
        public static final int INVALID_POSITION = -1;

        private Object mTag;
        private Drawable mIcon;
        private CharSequence mText;
        private CharSequence mContentDesc;
        private int mPosition = INVALID_POSITION;
        private View mCustomView;

        TabLayout mParent;
        TabView mView;
  .....
    }

Tab默認(rèn)圖標(biāo)在標(biāo)題的上方,還有xml里面設(shè)置TabItem的話,最終也是設(shè)置到Tab上捐康。關(guān)于Tab就說明這些仇矾,具體的大家可以自行測試。
可以看到關(guān)于TabLayout的實現(xiàn)也很簡單解总,就是給布局里面的TextView設(shè)置了文本顯示當(dāng)前是第幾個Tab贮匕。布局就更簡單了,F(xiàn)rameLayout中嵌套了一個TextView倾鲫,就不單獨給出了粗合。接下來我們就可以來瞅一瞅?qū)嶋H的使用效果了。


3 “填坑”與源碼解析

  • 源碼解析
    看到上面的效果圖是不是覺得很怪異乌昔?沒錯隙疚,我們所設(shè)置的Tab上的文字沒了,只有下面的指示條磕道。相信大家一通搜索后供屉,相信大家都知道了,最常見的就是分析源碼后得出結(jié)論溺蕉,被remove了A尕ぁ!疯特!接下來我們也來裝下文化人哗魂,看看怎么回事?
    首先是TabLayout的setupWithViewPager方法漓雅,一頓單擊后會到達(dá)如下源碼位置:
private void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh,
            boolean implicitSetup) {
        if (mViewPager != null) {
            // If we've already been setup with a ViewPager, remove us from it
            if (mPageChangeListener != null) {
                mViewPager.removeOnPageChangeListener(mPageChangeListener);
            }
            if (mAdapterChangeListener != null) {
                mViewPager.removeOnAdapterChangeListener(mAdapterChangeListener);
            }
        }
......
......
            if (adapter != null) {
                // Now we'll populate ourselves from the pager adapter, adding an observer if
                // autoRefresh is enabled
                setPagerAdapter(adapter, autoRefresh);
            }
......
......

            // Now update the scroll position to match the ViewPager's current item
            setScrollPosition(viewPager.getCurrentItem(), 0f, true);
        } else {
            // We've been given a null ViewPager so we need to clear out the internal state,
            // listeners and observers
            mViewPager = null;
            setPagerAdapter(null, false);
        }

        mSetupViewPagerImplicitly = implicitSetup;
    }

這里沒什么說的就是設(shè)置判斷移除录别、設(shè)置監(jiān)聽等操作,我們最主要去找到網(wǎng)上最多敘述問題所在的源碼位置邻吞,接下來我們看setPagerAdapter:

    void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
        if (mPagerAdapter != null && mPagerAdapterObserver != null) {
            // If we already have a PagerAdapter, unregister our observer
            mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
        }

        mPagerAdapter = adapter;

        if (addObserver && adapter != null) {
            // Register our observer on the new adapter
            if (mPagerAdapterObserver == null) {
                mPagerAdapterObserver = new PagerAdapterObserver();
            }
            adapter.registerDataSetObserver(mPagerAdapterObserver);
        }

        // Finally make sure we reflect the new adapter
        populateFromPagerAdapter();
    }

這段代碼主要是判斷之前的mPagerAdapter是否為空组题,不為空就移除DataSetObserver監(jiān)聽,將新的adapter設(shè)置進來并注冊上DataSetObserver監(jiān)聽抱冷。這里我們捕獲方法populateFromPagerAdapter一枚崔列,我們再看看它的實現(xiàn):

    void populateFromPagerAdapter() {
        removeAllTabs();

        if (mPagerAdapter != null) {
            final int adapterCount = mPagerAdapter.getCount();
            for (int i = 0; i < adapterCount; i++) {
                addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
            }

            // Make sure we reflect the currently set ViewPager item
            ......
        }
    }

哇塞!removeAllTabs旺遮,大家說得最多的一個方法赵讯,觀看方法名就很嚇人了,remove all tabs....看看它到底干了什么:

    public void removeAllTabs() {
        // Remove all the views
        for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
            removeTabViewAt(i);
        }

        for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
            final Tab tab = i.next();
            i.remove();
            tab.reset();
            sTabPool.release(tab);
        }

        mSelectedTab = null;
    }

它果真和它的命名一樣耿眉,遍歷remove了所有的tab瘦癌,并且將當(dāng)前選中也置為null。怎么辦跷敬?難道Google故意留下這么個坑?我們繼續(xù)看上面的populateFromPagerAdapter,會發(fā)現(xiàn)removeAllTabs后西傀,它會判斷adapter是否為空斤寇,不為空就調(diào)用了addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false)添加上了新的tab。

  • "填坑"思路
  1. 從上面的分析拥褂,我們發(fā)現(xiàn)如果要有tab還得去重寫adapter的getPageTitle方法娘锁。再看一段官方文檔中的說明:

If you're using a ViewPager together with this layout, you can call setupWithViewPager(ViewPager)
to link the two together. This layout will be automatically populated from the PagerAdapter
's page titles.

就是說官方推薦我們使用setupWithViewPager(ViewPager)來關(guān)聯(lián)Tablayout和Viewpager,且TabLayout會自動填充PagerAdapter的Title饺鹃。也就是說它會自動創(chuàng)建tab莫秆,并綁定為adapter的page
title。這下我們來改造下Activity:

public class MainActivity extends BaseActivity {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;
    private MainPagerAdapter mAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusTracker.init(getApplication());
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void initContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initView() {
        mTabLayout = findView(tabLayout);
        mViewPager = findView(R.id.viewPager);
        mAdapter = new MainPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        //官方推薦的綁定ViewPager方式
        mTabLayout.setupWithViewPager(mViewPager);
    }

    @Override
    protected void initData(@Nullable Bundle savedInstanceState) {

    }

    //ViewPager適配器  10個Fragment
    private class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return BlankFragment.newInstance(position);
        }

        //TabLayout會根據(jù)當(dāng)前page的title自動綁定tab
        @Override
        public CharSequence getPageTitle(int position) {
            return "Tab " + position;
        }

        @Override
        public int getCount() {
            return 10;
        }
    }
}

這就是新的Activity實現(xiàn)悔详,改動很小镊屎。我們首先刪除了initView中關(guān)于tab的初始化操作,然后重寫了FragmentPagerAdapter的getPageTitle方法茄螃。


  1. 我們既然知道他會自動為我們綁定tab缝驳,那么我們可以利用它自動幫我綁定tab,而不去重寫getPageTitle方法归苍,在綁定后去設(shè)置關(guān)于tab的顯示用狱。
public class MainActivity extends BaseActivity {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;
    private MainPagerAdapter mAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusTracker.init(getApplication());
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void initContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initView() {
        mTabLayout = findView(tabLayout);
        mViewPager = findView(R.id.viewPager);
        mAdapter = new MainPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        //官方推薦的綁定ViewPager方式
        mTabLayout.setupWithViewPager(mViewPager);
        int tabCount = mTabLayout.getTabCount();
        for (int i = 0; i < tabCount; i++) {
            //這里tab可能為null 根據(jù)實際情況處理吧
            mTabLayout.getTabAt(i).setText("Tab" + i);
        }
    }

    @Override
    protected void initData(@Nullable Bundle savedInstanceState) {

    }

    //ViewPager適配器  10個Fragment
    private class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return BlankFragment.newInstance(position);
        }

        @Override
        public int getCount() {
            return 10;
        }
    }
}

可以看到只是將initView中初始化Tab的位置調(diào)整到setupWithViewPager的后面,設(shè)置上我們需要的標(biāo)題拼弃。這里效果和上面一樣就不給出來占篇幅了夏伊。

  1. 上面我們依舊利用了setupWithViewPager自動為我們綁定tab的實現(xiàn),在分析源碼的時候發(fā)現(xiàn)它會調(diào)用ViewPager的addOnPageChangeListener和TabLayout的addOnTabSelectedListener吻氧,實現(xiàn)TabLayout與ViewPager的關(guān)聯(lián)溺忧。那么我們就自己來實現(xiàn)關(guān)聯(lián),不去使用官方推薦的setupWithViewPager方法綁定医男。
public class MainActivity extends BaseActivity {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;
    private MainPagerAdapter mAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusTracker.init(getApplication());
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void initContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initView() {
        mTabLayout = findView(tabLayout);
        mViewPager = findView(viewPager);
        mAdapter = new MainPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        //初始化tab
        for (int i = 0; i < 10; i++) {
            mTabLayout.addTab(mTabLayout.newTab().setText("item" + i));
        }
        //自己實現(xiàn)關(guān)聯(lián)
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
        mTabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
    }

    @Override
    protected void initData(@Nullable Bundle savedInstanceState) {

    }

    //ViewPager適配器  10個Fragment
    private class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return BlankFragment.newInstance(position);
        }

        @Override
        public int getCount() {
            return 10;
        }
    }
}

這段代碼砸狞,在initView中移除了官方推薦的設(shè)置相關(guān)代碼,自己初始化了tab并實現(xiàn)了關(guān)聯(lián)镀梭。注意這里我們改變了Tab的標(biāo)題作為區(qū)分刀森。效果也和上面一樣,只是改變了Tab的標(biāo)題报账。

4 其他問題

這樣TabLayout的簡單使用就介紹完了研底,這里還有兩個問題一個是TabLayout的標(biāo)題怎么就是大寫了,還有它的文字大小怎么改呢透罢?還記得我怎么在上一篇Android TabLayout系列之屬性中介紹的tabTextAppearance屬性么榜晦?我們就利用它來改變標(biāo)題字母大小寫和文字大小問題。先開看看TabLayout源碼中的默認(rèn)使用:

      mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
      R.style.TextAppearance_Design_Tab);


      <style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
          <item name="android:textSize">@dimen/design_tab_text_size</item>
          <item name="android:textColor">?android:textColorSecondary</item>
          <item name="textAllCaps">true</item>
      </style>

我們?yōu)門ablayout添加上tabTextAppearance屬性:

      app:tabTextAppearance="@style/TabLayoutStyle"

這里需要把具體的屬性定義到stytle中羽圃,這里有兩種方式:

    <style name="TabLayoutStyle" parent="TextAppearance.Design.Tab">
        <item name="android:textSize">16sp</item>
        <item name="textAllCaps">false</item>
    </style>
      <style name="TabLayoutStyle">
          <item name="android:textSize">16sp</item>
         //<item name="textAllCaps">false</item>
          <item name="android:textAllCaps">false</item>
      </style>

需要注意 parent="TextAppearance.Design.Tab"時乾胶,textAllCaps沒有android,當(dāng)不繼承的時候有沒有都可以。其實這里的字母大小寫识窿,不能算個坑斩郎。我們可以看material設(shè)計中所有tab的字母都是大寫,估計歪果仁標(biāo)題都習(xí)慣大寫吧喻频,或者是為了符合material設(shè)計缩宜,所以默認(rèn)的Tab被設(shè)置成了大寫。最后運行效果如下:


這里附上我的build.gradle甥温,有可能不同版本會有不一樣的效果锻煌,所以大家實際使用的時候需要注意一下:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.1"

    defaultConfig {
        applicationId "com.joker.demo"
        minSdkVersion 19
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

TabLayou的簡單使用就介紹這么多,其實真的是簡單使用姻蚓,主要是中間插入了一段源碼分析宋梧,所以看起來多了點。
附:

  1. Android TabLayout系列之屬性
  2. Android TabLayout系列之簡單使用
  3. Android TabLayout系列之進階使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末史简,一起剝皮案震驚了整個濱河市乃秀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌圆兵,老刑警劉巖跺讯,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異殉农,居然都是意外死亡刀脏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門超凳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愈污,“玉大人,你說我怎么就攤上這事轮傍≡荼ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵创夜,是天一觀的道長杭跪。 經(jīng)常有香客問我,道長驰吓,這世上最難降的妖魔是什么涧尿? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮檬贰,結(jié)果婚禮上姑廉,老公的妹妹穿的比我還像新娘。我一直安慰自己翁涤,他們只是感情好桥言,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布萌踱。 她就那樣靜靜地躺著,像睡著了一般限书。 火紅的嫁衣襯著肌膚如雪虫蝶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天倦西,我揣著相機與錄音,去河邊找鬼赁严。 笑死扰柠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疼约。 我是一名探鬼主播卤档,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼程剥!你這毒婦竟也來了劝枣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤织鲸,失蹤者是張志新(化名)和其女友劉穎舔腾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搂擦,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡稳诚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瀑踢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扳还。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖橱夭,靈堂內(nèi)的尸體忽然破棺而出氨距,到底是詐尸還是另有隱情,我是刑警寧澤棘劣,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布俏让,位于F島的核電站,受9級特大地震影響呈础,放射性物質(zhì)發(fā)生泄漏舆驶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一而钞、第九天 我趴在偏房一處隱蔽的房頂上張望沙廉。 院中可真熱鬧,春花似錦臼节、人聲如沸撬陵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巨税。三九已至蟋定,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間草添,已是汗流浹背驶兜。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留远寸,地道東北人抄淑。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像驰后,于是被迫代替她去往敵國和親肆资。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容