show code block

顯示具有 FragmentPagerAdapter 標籤的文章。 顯示所有文章
顯示具有 FragmentPagerAdapter 標籤的文章。 顯示所有文章

2017年11月28日 星期二

Android元件(TabLayout + ViewPager)– FragmentPagerAdapter簡易使用(二) 、TabLayout指示器

前言

除了ViewPager頁面的轉換,現在上面大多都還會有一個Tab
這邊使用我之前的DEMO 直接加上TabLayout
有兩篇可以先參考一下
 FragmentPagerAdapter簡易使用(一)
http://nikeru8.blogspot.tw/2017/11/androidfragmentpageradapterviewpager.html
還有
簡單ViewPager頁面 banner自動擴充實現
http://nikeru8.blogspot.tw/2017/11/androidviewpager-viewpager-banner.html

上面兩個demo都可以直接配合這次的TabLayout完成!
 如圖

今日實作


程式碼

First –

看圖說故事。
然後打上design
看到他後把他加入Gradle內,就開始使用囉




畫面xml拉好後
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.hello.kaiser.fragment.MainActivity">

    <android.support.design.widget.TabLayout
        android:id="@+id/view_tab"
        android:layout_width="match_parent"
        android:layout_height="44dp" />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/view_tab"
        android:background="@android:color/darker_gray" />

</RelativeLayout>
 



設定一下元件 findViewById
    private TabLayout mTab;
    mTab = (TabLayout) findViewById(R.id.view_tab);
 

讓我們來加入Tab吧
 mTab.addTab(mTab.newTab().setText("第一頁"));
 mTab.addTab(mTab.newTab().setText("第二頁"));
 

這就可以在上方產生兩個Tab

然後要讓ViewPager滑動時,上方Tab跟著滑動
 mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTab));
 

除了滑動之外
點擊Tab,下方的ViewPager當然也要有所動作
mTab.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
 

最簡單的使用方式就完成囉

如果你還想要再按下Tab時候,有額外的事件發生

可以設定她的監聽Listener
mTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
 

簡單的方式大致上就這樣

這邊再講一個新增Tab的方法

可以在xml直接上TabItem


<android.support.design.widget.TabLayout
        android:id="@+id/view_tab"
        android:layout_width="match_parent"
        android:layout_height="44dp">

        <android.support.design.widget.TabItem
            android:id="@+id/one"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="one" />

        <android.support.design.widget.TabItem
            android:id="@+id/two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="two" />

    </android.support.design.widget.TabLayout>
 
和ViewPager連動的部分運用上面的code在做連動

app:tabIndicatorColor指示條的顏色
app:tabIndicatorHeight指示條的高度
app:tabSelectedTextColor tab被選中時的字體顏色
app:tabTextColor tab未被選中時的字體顏色
app:tabMode="scrollable" : 默認是fixed:固定的,標籤很多時候會被擠壓,不能滑動。


 增加Tab的部分,這邊介紹了兩種,個人覺得使用代碼的方式呈現比較好,因為後台如果要新增Tab,這樣又要再xml上新增TabItem
如果使用代碼呈現,可以用for迴圈讓Tab的數量隨著後台的要求成長!



可能發生的問題

在普通的手機上都很正常,如果你在平板上造正常步驟設置妳的TabLayout
會有跑版問題,字體會往中間集中,下方那條指示器indicator也會變得很短。

在我百思不得其解下Rick大神解決了我的困難,在此歌頌一下師傅。

xml內設置
  <android.support.design.widget.TabLayout
       ...
        app:tabGravity="fill"
        app:tabMaxWidth="0dp"
       ...
        />
 
建議在使用TabLayout時都把這兩個加上,在平板上就不會跑版了。
感恩Seafood!讚嘆Seafood!



DEMO
https://github.com/nikeru8/FragmentPagerAdapterDemo/tree/addTabLayout

文獻:
http://www.jianshu.com/p/be1e8a1da639
http://givemepass-blog.logdown.com/posts/288943-how-to-use-tablayout

2017年11月27日 星期一

Android元件(FragmentPagerAdapter、ViewPager)– FragmentPagerAdapter簡易使用(一)

前言

之前寫了一個簡單的ViewPager範本。

簡單ViewPager頁面 banner自動擴充實現 
 http://nikeru8.blogspot.tw/2017/11/androidviewpager-viewpager-banner.html

 這篇偏向Banner

現在寫的FragmentPagerAdapter偏向頁面的使用方式


如下圖





重點程式碼

 step one FragmentPagerAdapter建構
先來看Adapter的部分 FragmentPagerAdapter

需要有幾個方法要複寫
 //必要建構子
    public adapter(FragmentManager fm) {
        super(fm);
    }

    //你想要顯示的Fragment
    @Override
    public Fragment getItem(int position) {
        return null;
    }

    //要顯示的筆數
    @Override
    public int getCount() {
        return 0;
    }
 

step two – Fragment

再來就是Fragment的部分
在開始前,先來看一下Fragment的生命週期

在這邊我們可以複寫onCreateonCreateView

並創建newInstance

newInstance可以自動創建
public static FragmentSingle newInstance() {
        //這邊設計呼叫Fragment的方式,Bundle內可以從activity > adapter 帶參數過來
        Bundle args = new Bundle();
        FragmentSingle fragment = new FragmentSingle();
        fragment.setArguments(args);
        return fragment;
    }

 
newInstance使用Bundle接參數帶入fragment
onCreate的地方真正的把參數帶到fragment

 //繼承fragment後,直接打newInstance會自動生成此方法,裡面都幫你建置好Bundle類了
    public static CreateFragment newInstance(int showType, String content) {
        //Bundle接收傳過來的參數
        Bundle args = new Bundle();
        args.putInt("showType", showType);
        args.putString("content", content);
        CreateFragment fragment = new CreateFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //帶入參數
        showType = getArguments().getInt("showType");
        content = getArguments().getString("content");
    }
 

接下來還要複寫兩種方法
onCreateViewonViewCreated

onCreateView:用來創建Layout xml的,你想創建什麼型態的xml也可以設定在這裡,有在上方圖片的生命週期內

onViewCreated:用來取得參數,理所當然的這個方法就會在onCreateView之後,使用getView()這個方法取得xml內的id

這邊舉個onViewCreated的使用
 
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    TextView message = getView().findViewById(R.id.item_one);
    message.setText(content);
}


大致上這樣。

這邊說明一下比較妥當的使用時機。

我是希望程式碼已不攏長,可讀性為主,所以可以的話,讓頁面長的雷同的地方再使用會比較好。

舉個例子:



像是這個App這頁面,有著高相似性的頁面,使用這方法就會是上上之選。

STEP THREE –

Fragment寫好後可以把它塞入Adapter內了

public class CustomFragmentAdapter extends FragmentPagerAdapter {

    String mTitleOne, mTitleTwo;

    public CustomFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    public void setDataOne(String messgae) {
        //這邊你可以在activity內獲取資料,再利用getItem傳入CreateFragment
        mTitleOne = messgae;
        notifyDataSetChanged();
    }

    public void setDataTwo(String message) {
        //這邊你可以在activity內獲取資料,再利用getItem傳入CreateFragment
        mTitleTwo = message;
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        //創作每一個Fragment內的內容
        if (position == 0) {//第一頁
            return new CreateFragment().newInstance(position, mTitleOne);
        } else {//第二頁
            return new CreateFragment().newInstance(position, mTitleTwo);
        }
    }

    @Override
    public int getCount() {
        //你得Fragment頁面數
        return 2;
    }
}
 

說明我寫在方法的上方。
此時你會看到我多寫了兩個方法setDataOnesetDataTwo
如果你兩個頁面的內容相差很多,要帶入不同的參數進去,可以使用這個方法和Activity要資料,在getItemnew不同的Fragment把資料帶進去。

當然你也可以直接寫在Adapter建構子內直接取值,但如果之後需要刷新fragment內的資料就要重新new一個Adapter,不是很聰明的作法。


完整程式碼

今日會動到的地方



簡單一個ViewPager
activity_main.xml
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.hello.kaiser.fragment.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/darker_gray" />

</RelativeLayout>
 
create_fragment_one.xml
create_fragment_one.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:background="@color/colorPrimary"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/item_one"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="one"
        android:textSize="40sp" />
</LinearLayout>
 

create_fragment_two.xml
create_fragment_two.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorAccent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/item_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="two"
        android:textSize="40sp" />
</LinearLayout>
 

畫面畫好了 來看程式碼吧

CustomFragmentAdapter.java
public class CustomFragmentAdapter extends FragmentPagerAdapter {

    String mTitleOne, mTitleTwo;

    public CustomFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    public void setDataOne(String messgae) {
        //這邊你可以在activity內獲取資料,再利用getItem傳入CreateFragment
        mTitleOne = messgae;
        notifyDataSetChanged();
    }

    public void setDataTwo(String message) {
        //這邊你可以在activity內獲取資料,再利用getItem傳入CreateFragment
        mTitleTwo = message;
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        //創作每一個Fragment內的內容
        if (position == 0) {//第一頁
            return new CreateFragment().newInstance(position, mTitleOne);
        } else {//第二頁
            return new CreateFragment().newInstance(position, mTitleTwo);
        }
    }

    @Override
    public int getCount() {
        //你得Fragment頁面數
        return 2;
    }
}

 

CreateFragment.java
public class CreateFragment extends Fragment {

    private int showType;
    private String content;
    private Context context;

    //繼承fragment後,直接打newInstance會自動生成此方法,裡面都幫你建置好Bundle類了
    public static CreateFragment newInstance(int showType, String content) {
        //Bundle接收傳過來的參數
        Bundle args = new Bundle();
        args.putInt("showType", showType);
        args.putString("content", content);
        CreateFragment fragment = new CreateFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //帶入參數
        showType = getArguments().getInt("showType");
        content = getArguments().getString("content");
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d("checkpoint", "onCreateView onCreateView");
        if ("0".equals(String.valueOf(showType))) {//第一頁
            return LayoutInflater.from(context).inflate(R.layout.create_fragment_one, null);
        } else if ("1".equals(String.valueOf(showType))) {//第二頁
            return LayoutInflater.from(context).inflate(R.layout.create_fragment_two, null);
        } else {
            return null;
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Log.d("checkpoint", "checkonViewCreatedpoint onViewCreated");

        super.onViewCreated(view, savedInstanceState);
        if (showType == 0) {//第一頁
            TextView message = getView().findViewById(R.id.item_one);
            message.setText(content);

        } else if (showType == 1) {//第二頁
            TextView message = getView().findViewById(R.id.item_two);
            message.setText(content);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.context = context;
    }
}

 

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private ViewPager mViewPager;
    private CustomFragmentAdapter mAdapter;

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

    private void initView() {
        mViewPager = (ViewPager) findViewById(R.id.view_pager);
    }

    private void initSet() {
        mAdapter = new CustomFragmentAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        mAdapter.setDataOne("你好第一頁");
        mAdapter.setDataTwo("歡迎光靈第二頁 hello ");
    }
}

 


DEMO
https://github.com/nikeru8/FragmentPagerAdapterDemo/tree/master



歡迎交流喔!



Fragment全集
 

Fragment的使用() ─ activity內放置Fragment
Fragment的使用() ─ activity內切換Fragment

Fragment 返回上一頁 OnBackPressed
Fragment點擊穿透
FragmentPagerAdapter

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...