2011年3月17日木曜日

Android タブをサイドにする

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



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

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

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


まずコンストラクタをみると

75 public TabWidget(Context context, AttributeSet attrs, int defStyle) {
76 super(context, attrs);
77
78 TypedArray a =
79 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget,
80 defStyle, 0);
81
82 mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true);
83 mDividerDrawable = a.getDrawable(R.styleable.TabWidget_divider);
84 mLeftStrip = a.getDrawable(R.styleable.TabWidget_tabStripLeft);
85 mRightStrip = a.getDrawable(R.styleable.TabWidget_tabStripRight);
86
87 a.recycle();
88
89 initTabWidget();
90 }


initTabWdiget() があやしい。。。


111 private void initTabWidget() {
112 setOrientation(LinearLayout.HORIZONTAL);
113 mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
114
115 final Context context = mContext;
116 final Resources resources = context.getResources();
117
118 if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
119 // Donut apps get old color scheme
120 if (mLeftStrip == null) {
121 mLeftStrip = resources.getDrawable(
122 com.android.internal.R.drawable.tab_bottom_left_v4);
123 }
124 if (mRightStrip == null) {
125 mRightStrip = resources.getDrawable(
126 com.android.internal.R.drawable.tab_bottom_right_v4);
127 }
128 } else {
129 // Use modern color scheme for Eclair and beyond
130 if (mLeftStrip == null) {
131 mLeftStrip = resources.getDrawable(
132 com.android.internal.R.drawable.tab_bottom_left);
133 }
134 if (mRightStrip == null) {
135 mRightStrip = resources.getDrawable(
136 com.android.internal.R.drawable.tab_bottom_right);
137 }
138 }
139
140 // Deal with focus, as we don't want the focus to go by default
141 // to a tab other than the current tab
142 setFocusable(true);
143 setOnFocusChangeListener(this);
144 }



112 setOrientation(LinearLayout.HORIZONTAL);


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

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

setOrientation(LinearLayout.VERTICAL);

を呼んであげます。


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



この TabWidget (つまりレイアウト的には LinearLayout) に子要素を追加する部分もカスタマイズする必要があります。

385 @Override
386 public void addView(View child) {
387 if (child.getLayoutParams() == null) {
388 final LinearLayout.LayoutParams lp = new LayoutParams(
389 0,
390 ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
391 lp.setMargins(0, 0, 0, 0);
392 child.setLayoutParams(lp);
393 }
394
395 // Ensure you can navigate to the tab with the keyboard, and you can touch it
396 child.setFocusable(true);
397 child.setClickable(true);
398
399 // If we have dividers between the tabs and we already have at least one
400 // tab, then add a divider before adding the next tab.
401 if (mDividerDrawable != null && getTabCount() > 0) {
402 ImageView divider = new ImageView(mContext);
403 final LinearLayout.LayoutParams lp = new LayoutParams(
404 mDividerDrawable.getIntrinsicWidth(),
405 LayoutParams.MATCH_PARENT);
406 lp.setMargins(0, 0, 0, 0);
407 divider.setLayoutParams(lp);
408 divider.setBackgroundDrawable(mDividerDrawable);
409 super.addView(divider);
410 }
411 super.addView(child);
412
413 // TODO: detect this via geometry with a tabwidget listener rather
414 // than potentially interfere with the view's listener
415 child.setOnClickListener(new TabClickListener(getTabCount() - 1));
416 child.setOnFocusChangeListener(this);
417 }


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


387 if (child.getLayoutParams() == null) {
388 final LinearLayout.LayoutParams lp = new LayoutParams(
389 0,
390 ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
391 lp.setMargins(0, 0, 0, 0);
392 child.setLayoutParams(lp);
393 }


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

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


public class SideTabWidget extends TabWidget {

public SideTabWidget(Context context) {
this(context, null);
}

public SideTabWidget(Context context, AttributeSet attrs) {
super(context, attrs);

setOrientation(LinearLayout.VERTICAL);
}

@Override
public void addView(View child) {
if (child.getLayoutParams() == null) {
final LinearLayout.LayoutParams lp = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f);
lp.setMargins(0, 0, 0, 0);
child.setLayoutParams(lp);
}
super.addView(child);
}
}



<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="10dip" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@color/basic_white2"
android:padding="10dip"
/>
<layoutbook.example.sidetab.SideTabWidget
android:orientation="vertical"
android:id="@android:id/tabs"
android:layout_width="60dip"
android:layout_height="fill_parent" />
</LinearLayout>
</TabHost>

0 件のコメント:

コメントを投稿