2011年3月17日木曜日

Android タブをサイドにする

こういうのってなんていうのかな?
横タブ?



結構簡単にできちゃいました。

タブのつまみ部分は TabWidget というクラスです。

TabWidget のソースをみてみればわかりますが、このクラスは LinearLayout を継承しています。
つまり、各つまみは LinearLayout の子要素ということになります。


まずコンストラクタをみると
  1. 75     public TabWidget(Context context, AttributeSet attrs, int defStyle) {  
  2. 76         super(context, attrs);  
  3. 77   
  4. 78         TypedArray a =  
  5. 79             context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget,  
  6. 80                     defStyle, 0);  
  7. 81   
  8. 82         mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true);  
  9. 83         mDividerDrawable = a.getDrawable(R.styleable.TabWidget_divider);  
  10. 84         mLeftStrip = a.getDrawable(R.styleable.TabWidget_tabStripLeft);  
  11. 85         mRightStrip = a.getDrawable(R.styleable.TabWidget_tabStripRight);  
  12. 86   
  13. 87         a.recycle();  
  14. 88   
  15. 89         initTabWidget();  
  16. 90     }  


initTabWdiget() があやしい。。。

  1. 111     private void initTabWidget() {  
  2. 112         setOrientation(LinearLayout.HORIZONTAL);  
  3. 113         mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;  
  4. 114   
  5. 115         final Context context = mContext;  
  6. 116         final Resources resources = context.getResources();  
  7. 117   
  8. 118         if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {  
  9. 119             // Donut apps get old color scheme  
  10. 120             if (mLeftStrip == null) {  
  11. 121                 mLeftStrip = resources.getDrawable(  
  12. 122                         com.android.internal.R.drawable.tab_bottom_left_v4);  
  13. 123             }  
  14. 124             if (mRightStrip == null) {  
  15. 125                 mRightStrip = resources.getDrawable(  
  16. 126                         com.android.internal.R.drawable.tab_bottom_right_v4);  
  17. 127             }  
  18. 128         } else {  
  19. 129             // Use modern color scheme for Eclair and beyond  
  20. 130             if (mLeftStrip == null) {  
  21. 131                 mLeftStrip = resources.getDrawable(  
  22. 132                         com.android.internal.R.drawable.tab_bottom_left);  
  23. 133             }  
  24. 134             if (mRightStrip == null) {  
  25. 135                 mRightStrip = resources.getDrawable(  
  26. 136                         com.android.internal.R.drawable.tab_bottom_right);  
  27. 137             }  
  28. 138         }  
  29. 139   
  30. 140         // Deal with focus, as we don't want the focus to go by default  
  31. 141         // to a tab other than the current tab  
  32. 142         setFocusable(true);  
  33. 143         setOnFocusChangeListener(this);  
  34. 144     }  


  1. 112         setOrientation(LinearLayout.HORIZONTAL);  


でがっつり horizontal 指定してますね。

なので、TabWdiget を継承した独自クラスを作って、そのコンストラクタで super() を読んだ後に

setOrientation(LinearLayout.VERTICAL);

を呼んであげます。


これだけではダメなんです。



この TabWidget (つまりレイアウト的には LinearLayout) に子要素を追加する部分もカスタマイズする必要があります。
  1. 385     @Override  
  2. 386     public void addView(View child) {  
  3. 387         if (child.getLayoutParams() == null) {  
  4. 388             final LinearLayout.LayoutParams lp = new LayoutParams(  
  5. 389                     0,  
  6. 390                     ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);  
  7. 391             lp.setMargins(0000);  
  8. 392             child.setLayoutParams(lp);  
  9. 393         }  
  10. 394   
  11. 395         // Ensure you can navigate to the tab with the keyboard, and you can touch it  
  12. 396         child.setFocusable(true);  
  13. 397         child.setClickable(true);  
  14. 398   
  15. 399         // If we have dividers between the tabs and we already have at least one  
  16. 400         // tab, then add a divider before adding the next tab.  
  17. 401         if (mDividerDrawable != null && getTabCount() > 0) {  
  18. 402             ImageView divider = new ImageView(mContext);  
  19. 403             final LinearLayout.LayoutParams lp = new LayoutParams(  
  20. 404                     mDividerDrawable.getIntrinsicWidth(),  
  21. 405                     LayoutParams.MATCH_PARENT);  
  22. 406             lp.setMargins(0000);  
  23. 407             divider.setLayoutParams(lp);  
  24. 408             divider.setBackgroundDrawable(mDividerDrawable);  
  25. 409             super.addView(divider);  
  26. 410         }  
  27. 411         super.addView(child);  
  28. 412   
  29. 413         // TODO: detect this via geometry with a tabwidget listener rather  
  30. 414         // than potentially interfere with the view's listener  
  31. 415         child.setOnClickListener(new TabClickListener(getTabCount() - 1));  
  32. 416         child.setOnFocusChangeListener(this);  
  33. 417     }  


LinearLayout に子要素を追加するメソッドの addView で

  1. 387         if (child.getLayoutParams() == null) {  
  2. 388             final LinearLayout.LayoutParams lp = new LayoutParams(  
  3. 389                     0,  
  4. 390                     ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);  
  5. 391             lp.setMargins(0000);  
  6. 392             child.setLayoutParams(lp);  
  7. 393         }  


と、width に 0, height に ViewGroup.LayoutParams.MATCH_PARENT が指定されています。
これを反対にします。

ということで完成コードはこんな感じ。

  1. public class SideTabWidget extends TabWidget {  
  2.   
  3.  public SideTabWidget(Context context) {  
  4.   this(context, null);  
  5.  }  
  6.   
  7.  public SideTabWidget(Context context, AttributeSet attrs) {  
  8.   super(context, attrs);  
  9.   
  10.   setOrientation(LinearLayout.VERTICAL);  
  11.  }  
  12.   
  13.  @Override  
  14.  public void addView(View child) {  
  15.   if (child.getLayoutParams() == null) {  
  16.    final LinearLayout.LayoutParams lp = new LayoutParams(  
  17.      ViewGroup.LayoutParams.MATCH_PARENT, 01.0f);  
  18.    lp.setMargins(0000);  
  19.    child.setLayoutParams(lp);  
  20.   }  
  21.   super.addView(child);  
  22.  }  
  23. }  


  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <TabHost xmlns:android="http://schemas.android.com/apk/res/android"  
  3.   android:id="@android:id/tabhost"  
  4.   android:layout_width="fill_parent"  
  5.   android:layout_height="fill_parent"  
  6.   android:paddingBottom="10dip" >  
  7.   <LinearLayout  
  8.     android:orientation="horizontal"  
  9.     android:layout_width="fill_parent"  
  10.     android:layout_height="fill_parent"  
  11.     >  
  12.     <FrameLayout  
  13.       android:id="@android:id/tabcontent"  
  14.       android:layout_width="0dip"  
  15.       android:layout_height="fill_parent"  
  16.       android:layout_weight="1"  
  17.       android:background="@color/basic_white2"  
  18.       android:padding="10dip"  
  19.       />  
  20.     <layoutbook.example.sidetab.SideTabWidget  
  21.       android:orientation="vertical"  
  22.       android:id="@android:id/tabs"  
  23.       android:layout_width="60dip"  
  24.       android:layout_height="fill_parent" />  
  25.   </LinearLayout>  
  26. </TabHost>  

0 件のコメント:

コメントを投稿