使用 Android SlidingTab 製作可滑動標籤

SlidingTab

舊式的標籤(Tab)在製作上很繁鎖,操作靈活性也很差。Sliding Tab 讓這些缺點都消失了,要加入一個標籤頁(page),只要簡單的加入一個新的 Fragment 就能辦到,而且在 Tab 數量很多的情況下,連標籤列本身都能夠左右滑動來顯示。

Sliding Tab 可以很容易的指定該 Tab 被選取時,底線指示器的顏色,而且每個 Tab 都可以指定不同的顏色。

開始之前的說明

本篇文章中的 Sliding Tab 程式碼是由 Android 官方 Sample 檔(SlidingTabsBasic) 修改而來,而經過程式碼的抽取調整後,Tab 的部份可以重覆利用於其他專案,後面文章中會在說明。

如果你想直接使用,也有人把它改寫成套件,可以直接拿來用,請參考 astuetz/PagerSlidingTabStrip

此文章中的範例會使用 Android 5.x 的 Toolbar,這方面的內容可以參考 如何將 Android ActionBar 轉換到 Toolbar

layout

首先是主 Activity 的 layout,主要有一個 FrameLayout,用來放置主要的 TabFragment。

activity_main.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:orientation="vertical">

    <include layout="@layout/toolbar" />

    <FrameLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical"
          android:id="@+id/content_fragment" />

</LinearLayout>
說明:
這裡先記住 FrameLayout 的 id 是 content_fragment。

frg_tab.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:orientation="vertical">

    <com.tonycube.slidingtabsdemo.tab.SlidingTabLayout
          android:id="@+id/tabs"
          android:layout_width="match_parent"
          android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1" />

</LinearLayout>
說明:
這是 TabFragment 的 layout,SlidingTabLayout 是 Sample 中的程式碼,用來顯示 Tab;ViewPager 用來顯示 Fragment,並且讓這些 Fragment 可以左右滑動。

frg_common.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".fragment.BookFragment" >

    <TextView
        android:id="@+id/txtName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="BOOKs"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>
說明:
這是一個共用的 fragment layout,正常情況可能是你的每個 Fragment 都會有自己的 layout,這裡為了簡化,所以全都用一樣的,之後會以程式碼設定 text 來顯示不一樣的內容。

MainActivity.java

public class MainActivity extends ActionBarActivity {

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

        initToolbar();
        initTabFragment(savedInstanceState);
    }

    private void initToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        actionBar.setTitle("SlidingTabs Demo");
    }

    private void initTabFragment(Bundle savedInstanceState){
        if (savedInstanceState == null) {
            TabFragment tabFragment = new TabFragment();

            getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.content_fragment, tabFragment)
                .commit();
        }
    }

}
說明:
繼承 ActionBarActivity,使用 R.layout.activity_main,建立 TabFragment 的實體,使用 FragmentManager 加入 R.id.content_fragment 中。

處理 Tab

這裡從 Sample 中取出 SlidingTabLayout.java 及 SlidingTabStrip.java 兩個檔案,可以直接使用。另外,我加入一個 BaseFragment.java,用來讓之後的 Fragment 繼承,方便指定 Tab 的指示器及分隔線的顏色,還有標籤名稱。

BaseFragment.java

public class BaseFragment extends Fragment {

    private String title = "";
    private int indicatorColor = Color.BLUE;
    private int dividerColor = Color.GRAY;

    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public int getIndicatorColor() {
        return indicatorColor;
    }
    public void setIndicatorColor(int indicatorColor) {
        this.indicatorColor = indicatorColor;
    }
    public int getDividerColor() {
        return dividerColor;
    }
    public void setDividerColor(int dividerColor) {
        this.dividerColor = dividerColor;
    }

}
說明:
SlidingTabLayout.javaSlidingTabStrip.java 的部份請直接看原始檔,我幾乎沒什麼修改。這 3 個檔案全都放在 tab package 之中,其他專案就可以直接重覆使用。

TabFragmentPagerAdapter.java

public class TabFragmentPagerAdapter extends FragmentPagerAdapter {

    LinkedList<BaseFragment> fragments = null;

    public TabFragmentPagerAdapter(FragmentManager fm, LinkedList<BaseFragment> fragments) {
        super(fm);
        if (fragments == null) {
            this.fragments = new LinkedList<BaseFragment>();
        }else{
            this.fragments = fragments;
        }
    }

    @Override
    public BaseFragment getItem(int position) {
        return fragments.get(position);
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return fragments.get(position).getTitle();
    }

}
說明:
TabFragmentPagerAdapter 繼承 FragmentPagerAdapter。這個檔案也是可以重覆使用的。

TabFragment.java

public class TabFragment extends Fragment {

    private SlidingTabLayout tabs;
    private ViewPager pager;
    private FragmentPagerAdapter adapter;

    public static Fragment newInstance(){
        TabFragment f = new TabFragment();
        return f;
    }

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        //adapter
        final LinkedList<BaseFragment> fragments = getFragments();
        adapter = new TabFragmentPagerAdapter(getFragmentManager(), fragments);
        //pager
        pager = (ViewPager) view.findViewById(R.id.pager);
        pager.setAdapter(adapter);
        //tabs
        tabs = (SlidingTabLayout) view.findViewById(R.id.tabs);
        tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {

            @Override
            public int getIndicatorColor(int position) {
                return fragments.get(position).getIndicatorColor();
            }

            @Override
            public int getDividerColor(int position) {
                return fragments.get(position).getDividerColor();
            }
        });
        tabs.setBackgroundResource(R.color.color_primary);
        tabs.setViewPager(pager);
    }

    private LinkedList<BaseFragment> getFragments(){
        int indicatorColor = Color.parseColor(this.getResources().getString(R.color.color_accent));
        int dividerColor = Color.TRANSPARENT;

        LinkedList<BaseFragment> fragments = new LinkedList<BaseFragment>();
        fragments.add(BookFragment.newInstance("Book", indicatorColor, dividerColor));
        fragments.add(CookFragment.newInstance("Cook", indicatorColor, dividerColor));
        fragments.add(FoodFragment.newInstance("Food", indicatorColor, dividerColor));
        fragments.add(GoodFragment.newInstance("Good", Color.BLUE, dividerColor));
        fragments.add(LookFragment.newInstance("Look", Color.CYAN, dividerColor));
        fragments.add(WoodFragment.newInstance("Wood", Color.MAGENTA, dividerColor));
        return fragments;
    }
}
說明:
這裡就是把前面的東西組合起來。

我們在 getFragments() 方法裡去建立想要呈現的標籤頁。indicatorColor 是底線指示器的顏色,通常會統一一個顏色,當然你也可以各別指定;分隔線的顏色也可以指定,這裡設為透明。

這些 fragments 送給 TabFragmentPagerAdapter 後,再把 TabFragmentPagerAdapter 送給 ViewPager,最後,把 ViewPager 送給 SlidingTabLayout 就完成了。

tabs.setBackgroundResource(R.color.color_primary); 這一行是指定 tab 的背景色,這裡指定為和 Toolbar 相同的主色。

最後呈現的結果: 範例程式碼:github - tony915/SlidingTabDemo
註:如果要在 Tab 上使用圖示,請參考 如何在 Android SlidingTab 加入 Icon 圖示

參考資料

本文網址:http://blog.tonycube.com/2015/06/android-slidingtab.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

51 則留言

  1. 作者已經移除這則留言。

    回覆刪除
    回覆
    1. 它已經跟你說了「attempting to use incompatible return type」
      你回傳的資料型態不對,必須是 BaseFragment

      刪除
  2. 作者已經移除這則留言。

    回覆刪除
  3. 回覆
    1. 請參考這篇 SlidingTab with Icon ( http://blog.tonycube.com/2015/08/android-slidingtab-with-icon.html#more )

      刪除
  4. 請問我用Android Studio 開發 照著這個步驟也可以嗎??
    因為有些地方好像有紅色的線呢@@

    回覆刪除
  5. 您好,請問一下,小弟於第一個tab做一個新的layout ,取名為a.xml,想在a.xml上面放置相關的button,請問這樣Activity要寫在哪裡呢?
    我試著增加A.java,但一直無法與A.xml相關聯…

    回覆刪除
    回覆
    1. 我不知道要怎麼回答你的問題,你要不要把範例檔下載回去看看。

      刪除
  6. 請問要怎麼調整每個Tab的寬度呢?
    或是如果我想讓他們平均螢幕寬度,呈現滿版狀態應該要在哪修改?
    我有試著在SlidingTabLayout.java 中的 protected TextView createDefaultTabView(Context context)添加以下程式碼...但是沒有反應
    不知道弄錯了什麼...

    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    textView.setWidth(size.x / 5);

    回覆刪除
    回覆
    1. 在createDefaultTabView()中你改的是Tab內的TextView,而不是Tab本身,
      也就是Tab(View類別)之下有Title(TextView)或其他如ICON等元件。


      要改Tab寬,要在 populateTabStrip() 中最後要被加入 TabStrip 前做修改,
      程式碼如下:
      1.
      //下面這行放在 for 外面才不會重覆計算
      //除以多少表示一次顯示幾個Tab
      final int w = getResources().getDisplayMetrics().widthPixels / 3;

      2.
      tabView.setOnClickListener(tabClickListener);
      //////////在這之後/////////

      //在原本的程式碼中加入以下3行
      //先取出layout,改變寬後再存回去
      ViewGroup.LayoutParams param = tabView.getLayoutParams();
      param.width = w;
      tabView.setLayoutParams(param);

      /////////////在這之前/////////
      mTabStrip.addView(tabView);

      刪除
    2. 可以了~~
      Tony大,太感謝你了^_^

      刪除
    3. 我加了這幾個程式碼,但是卻出現這樣的錯誤訊息Caused by: java.lang.NullPointerException: Attempt to write to field 'int android.view.ViewGroup$LayoutParams.width' on a null object reference
      是我哪裡弄錯了嗎?
      private void populateTabStrip() {
      final TabFragmentPagerAdapter adapter = (TabFragmentPagerAdapter) mViewPager.getAdapter();
      final OnClickListener tabClickListener = new TabClickListener();
      final int w = getResources().getDisplayMetrics().widthPixels / 4;
      for (int i = 0; i < adapter.getCount(); i++) {
      View tabView = null;
      TextView tabTitleView = null;
      ImageView tabIcon = null;
      if (mTabViewLayoutId != 0) {
      tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,false);
      tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
      tabIcon = (ImageView) tabView.findViewById(mTabViewIconId);
      }
      if (tabView == null) {
      tabView = createDefaultTabView(getContext());
      }
      if (tabTitleView == null && TextView.class.isInstance(tabView)) {
      tabTitleView = (TextView) tabView;
      }
      tabTitleView.setText(adapter.getPageTitle(i));
      tabView.setOnClickListener(tabClickListener);

      ViewGroup.LayoutParams param = tabView.getLayoutParams();
      param.width = w;
      tabView.setLayoutParams(param);

      mTabStrip.addView(tabView);
      }
      }

      刪除
    4. 你有試過不加這3行
      ViewGroup.LayoutParams param = tabView.getLayoutParams();
      param.width = w;
      tabView.setLayoutParams(param);
      可以執行嗎?

      錯誤訊息指出,你的 param.width 是 null,但是看起來應該不會這樣,

      或是可以試試看改用
      ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(w, ViewGroup.LayoutParams.MATCH_PARENT);
      tabView.setLayoutParams(param);
      但我不確定這樣可不可行,
      還是要找一下為什麼你的 tabView.getLayoutParams() 會回傳 null

      刪除
    5. Tony老師,改成這個程式碼後就可以了耶~~~
      ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(w, ViewGroup.LayoutParams.MATCH_PARENT);
      tabView.setLayoutParams(param);
      謝謝老師!!!!

      我之前嘗試時,有想過直接給w值,像這樣
      ViewGroup.LayoutParams param = tabView.getLayoutParams();
      param.width = 30;
      tabView.setLayoutParams(param);
      但是程式一樣不能跑><
      刪掉這三行後,倒是可以跑出來,所以還是不太知道這三行出了甚麼問題




      刪除
  7. 您好,
    我照您的範例做出有3個Tab的SlidingTabs,我發現在初始化後、不管怎麼切換Tab
    中間的Tab(Fragment)都不會觸發onPause, onResume, onDestroyView, onCreateView....等
    但左右二邊的Fragment都會觸發到,這就導致我的App切換到背景閒置很久的情況下
    再點回App時,Tab內的Fragment都變成一片空白,左右滑動後二邊的Tab會重新產生UI
    但中間的Tab始終呈現一片空白的模樣,必須要關閉App重開才可以。
    請問這要如何解決呢? 謝謝~~

    回覆刪除
    回覆
    1. 我試不出你遇到的情況,不過有人跟你一樣(http://stackoverflow.com/questions/25398109/tabs-show-blank-fragment-on-returning-to-fragment-second-time)

      做法是把 TabFragment class 的 onViewCreated() 方法中的
      adapter = new TabFragmentPagerAdapter(getFragmentManager(), fragments);
      換成
      adapter = new TabFragmentPagerAdapter(getChildFragmentManager(), fragments);

      getChildFragmentManager() 會取得私有的管理器,但我不確定這樣是不是能解決,
      如果你有解決了,麻煩在回文一下,謝謝。

      刪除
    2. 謝謝熱心的Tony大,這篇文章改成使用 getChildFragmentManager() 我也有看到,後來測試中間的Tab在閒置過久回到前景會產生UI了,但會衍生另一個問題。
      原本使用getFragmentManager()時,Tab下的Fragment呼叫startActivityForResult(Intent, requestcode)去啟動另一Activity後,回傳的onActivityResult()也是該Fragment會接收到
      換成使用getChildFragmentManager()後,結果onActivityResult只有使用該TabFragment的MainActivity會觸發onActivityResult。

      不過這問題還算好解決,在統一由MainActivity接收再根據來源的requestcode再手動去分派到子Fragment

      刪除
    3. 了解,感謝你的測試結果及心得 :)

      刪除
  8. 不好意思,因為我試著用你的範例來執行
    結果發現程式會無法開啟
    嘗試著去找出問題,可是實在不知道這是為甚麼會這樣
    所以想問一下有可能是哪邊出了問題
    感謝你

    回覆刪除
    回覆
    1. 看看有什麼錯誤訊息,不過應該都是出在設定的問題,程式碼本身是沒問題的,
      像是使用的 Android API 版本、SDK build tool 版本、support library 有沒有錯誤
      之前這個程式是用 Eclipse 寫的,所以如果你匯入 AS 可能要調整設定之類的。

      刪除
  9. 你好,我用了你上面这个例子,但是我想改变tab的宽度,tab上面字体大小。TAB_VIEW_TEXT_SIZE_SP
    TAB_VIEW_PADDING_DIPS,我改了上面这些为什么没有变化,应该怎么改的?请教一下,谢谢。

    回覆刪除
    回覆
    1. 前面"盛夏清風"的問題有說明怎麼改變 Tab 的寬度,你可以看一下,
      在 SlidingTabLayout.java 中,找到 populateTabStrip()
      在 mTabStrip.addView(tabView); 這行之前加入

      ViewGroup.LayoutParams param = tabView.getLayoutParams();
      param.width = w;
      tabView.setLayoutParams(param);

      其中 w 就是你要指定的 Tab 的寬度。
      ----
      至於 Tab 字體大小,要多加一行

      tabTitleView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);//改變Tab字大小

      在 tabTitleView.setText(adapter.getPageTitle(i)); 這行前面或後面都可以
      因為 TAB_VIEW_TEXT_SIZE_SP 原本只在 createDefaultTabView() 裡有用,
      你現在在 populateTabStrip() 中的 addView 之前統一做設定,
      這樣前面不管前面怎麼設定,最後都會一併被修改。

      刪除
    2. 非常感谢你的回复,字体已经解决。上面我没说清楚,我还想改的是tab上下方向的宽度,不是水平的宽度,我看了上面的回复,自己试了下
      final int h;
      ViewGroup.LayoutParams param1 = tabView.getLayoutParams();
      param1.height = h;
      tabView.setLayoutParams(param1);

      但是这么弄效果不对,我想让tab上下方向变得更宽一点,应该怎么改,谢谢。

      刪除
    3. 我解决了,原来是改padding,就可以实现。

      刪除
  10. 您好
    請問要怎麼移動到畫面下方?

    回覆刪除
    回覆
    1. 你試試看在 frg_tab.xml
      把 SlidingTabLayout 和 Viewpager 對換看看。

      刪除
  11. 您好,這個範例很實用,謝謝您

    我在 Android Studio API23 上測試,發現在切換 tab 的時候都會出現以下的 waring

    05-26 08:58:42.134 32030-32030/com.e_yo.slidingtab W/FragmentManager: moveToState: Fragment state for Fragment_PPPoE{9532fe8 #1 id=0x7f0c0055 android:switcher:2131492949:1} not updated inline; expected state 3 found 2

    不曉得您有遇過嗎?
    謝謝您

    回覆刪除
    回覆
    1. 您好,我找到解決方法了,應該是 api 問題,將版本降級後就可以了。在 build.gradle 中,將
      compile 'com.android.support:appcompat-v7:23.4.0'
      換成
      compile 'com.android.support:appcompat-v7:23.0.1'
      就可以了

      謝謝您

      刪除
  12. 好文!謝謝 幫你點一下廣告 XD

    回覆刪除
  13. 老師您好,我專案匯入到android studio裡,匯入後因為actionbar不支援緣故,我改成AppCompatActivity但執行時還是直接報錯:
    08-30 07:37:39.618 11671-11671/com.tonycube.slidingtabsdemo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.tonycube.slidingtabsdemo, PID: 11671
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tonycube.slidingtabsdemo/com.tonycube.slidingtabsdemo.MainActivity}: java.lang.IllegalArgumentException: AppCompat does not support the current theme features
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.access$800(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    Caused by: java.lang.IllegalArgumentException: AppCompat does not support the current theme features
    at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:363)
    at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:246)
    at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
    at com.tonycube.slidingtabsdemo.MainActivity.onCreate(MainActivity.java:18)
    at android.app.Activity.performCreate(Activity.java:5990)
    因為字數關係,所以只複製部分字數
    我看了一下是因為AppCompat does not support the current theme features,我照了一些網友建議的方法但還是不行,
    所以來請教您,謝謝您

    回覆刪除
    回覆
    1. 看一下 build.gradle 中的 dependencies 裡面,
      com.android.support:appcompat-v7:
      com.android.support:design:
      com.android.support:support-v4:
      是不是都有使用最新版本,SDK記得要先更新,
      這個問題是出在 theme 的某些功能在某個版本中沒有,
      //
      通常這樣就可以了,
      如果不行,你可以把 theme 先換成使用預設的,如果可以執行,
      那只要找出是哪個 theme 的功能不支援,換成支援的版本就可以,例如 Theme.AppCompat
      或是新增版本,讓這個功能只在該 Android 版本以上才執行。


      刪除
    2. 老師,我後來把theme_material.xml裡的
      item name="android:windowNoTitle>"true</item
      把"android:"去掉就可以了。謝謝老師!

      刪除
  14. 老師你好!
    我有兩個大問題要提問,
    第一個是frg_common.xml中的說明『正常情況可能是你的每個 Fragment 都會有自己的 layout,這裡為了簡化,所以全都用一樣的』,
    那如果我要做都有各自的layout,然後想要做的是有4個tab,依序為 主頁、店家、購物車、其他,那frg_common.xml是不是將它設計成我要的主頁就可以了?
    然後TabFragment.java的最下方我add我做的個別java檔,
    各自java檔中的『return inflater.inflate(R.layout.frg_common, container, false)』的.frg_common,
    修改為各自的layout就能達成有切換到各自分頁的layout效果對吧?

    第二個問題是TabFragmentPagerAdapter說明中的繼承FragmentPagerAdapter,是我本身也需要建置一個FragmentPagerAdapter的java檔嗎?

    回覆刪除
    回覆
    1. (1)例如:
      主頁=> frg_main.xml
      店家=> frg_shop.xml
      購物車=> frg_shopcart.xml
      其他=> frg_other.xml
      這樣,各自的 fragement 載入各自的頁面設定。


      (2)
      TabFragmentPagerAdapter 會在 Tab 指向某個頁面時,回傳相對應的 Fragment,這個範例的程式碼是可以直接用的,如果你要寫自己版本的話,只要繼承 FragmentPagerAdapter 就可以了,可能叫 xxxFragmentPagerAdapter 之類的,但只要一個。

      刪除
  15. 你好 我想請問一下就是我試著做了,但是出現一個問題我一直無法解決。
    在MainActivity中我用的是Activity,然後getSupportFragmentManager()我修改為getFragmentManager()。
    但在.add出錯了,她告訴我cannot resolve method .add(int, com.****.TabFragment)
    請問是哪邊出了錯?

    回覆刪除
    回覆
    1. 請問為何我之前留的兩個我都看不到????

      刪除
    2. 不能繼承 Activity, 而是 ActionBarActivity,
      因為 Android 版本太多,所以加了很多 Supprt 的 library,

      Activity 認不得 getSupportFragmentManager(),而它自己有 getFragmentManager(),
      兩個是不同的,雖然是做相同的事。

      你要注意的是 API 版本,要向下相容,就必須使用 Support 版的程式碼,要注意 import 的是 v4,v7還是沒有版本號的,不同版本的相同名稱的方法並不相容。

      刪除
    3. 另外,你的發文被系統擋掉了,我也不知道它是怎麼判斷的~

      刪除
  16. 之前也是根據老師所寫的轉換成toolbar文章做,但是只要使用Activity以外的就會崩潰,所以才會修改成Activity。

    我所使用的是API23,所以建議將專案的部分轉換成ActionBarActivity嗎?
    import的部分是使用v7版本
    若如果先依造Activity的話那.add這樣如何解決?

    回覆刪除
    回覆
    1. 總之,你要用相對應的版本的類別及方法,
      如果你是參考範例程式碼來寫,通常都不會錯,
      出錯的原因是用錯版本或方法

      例如:
      https://developer.android.com/reference/android/app/Fragment.html
      這個非 support 版的 Fragment 繼承自 android.app.Fragment,
      在 API level 11 被加入,你用的 Activity 就是要用這個版本;

      https://developer.android.com/reference/android/support/v4/app/Fragment.html
      這是 support-v4 版本的 Fragment 繼承自 android.support.v4.app.Fragment,
      如果你拿給 Activity 的非 support 方法用,當然就發生錯誤。

      刪除
    2. 那我再試試看

      想請問老師寫程式的習慣,是否都是統一繼承ActionbarAtivity方式來寫,因為我屬於新手,所以很不了解,所以常用繼承Ativity方式。
      但之前有過作一個loading部分是使用繼承Ativity方式,然後跳轉到自己做tabhost部分是繼承ActionbarAtivity方式是可以正常使用的
      那這樣的做法是不是不建議這樣子?

      刪除
    3. 你如果是在練習的話,可以先都用最新的 API,
      等之後有需要向下相容的時候,在去改用 Support 的版本,這樣環境比較單純,
      重點是,你在寫的時候,要想清楚是用哪個版本的程式碼就好,
      用法都差不多,只是版本不同的問題而已。

      刪除
  17. 老師我想問一下,底線可以更改高度嗎

    回覆刪除
    回覆
    1. 修改 tab / SlidingTabStrip.java
      中的 SELECTED_INDICATOR_THICKNESS_DIPS = 8;//8
      的值

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。