実は style の設定で合うようにすることができます。
以下では、つまみ部分に星型の画像を、トラック部分に 9patch の画像を用意しています。
つまみ
プログレス
トラックベース
res/values/style.xml で次のように定義し
- <resources>
- <style name="AppTheme" parent="android:Theme.Light">
- <item name="android:seekBarStyle">@style/MySeekBar</item>
- </style>
- <style name="MySeekBar" parent="@android:style/Widget.SeekBar">
- <item name="android:indeterminateOnly">false</item>
- <item name="android:progressDrawable">@drawable/seekbar</item>
- <item name="android:indeterminateDrawable">@drawable/seekbar</item>
- <item name="android:thumb">@drawable/seekbar_thumb</item>
- </style>
- </resources>
確かにバーの進み具体がつまみの中心になっていません。
左端
少し進んだところ
右端
どうしてこうなるかを理解するには、実際のプログラムでどう描画されるのかを知る必要があります。
1. 初期値を知る
上記では parent="@android:style/Widget.SeekBar" しているので、このスタイルで定義されている値をみてみましょう。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/res/res/values/styles.xml#397
- 397 <style name="Widget.SeekBar">
- 398 <item name="android:indeterminateOnly">false</item>
- 399 <item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
- 400 <item name="android:indeterminateDrawable">@android:drawable/progress_horizontal</item>
- 401 <item name="android:minHeight">20dip</item>
- 402 <item name="android:maxHeight">20dip</item>
- 403 <item name="android:thumb">@android:drawable/seek_thumb</item>
- 404 <item name="android:thumbOffset">8dip</item>
- 405 <item name="android:focusable">true</item>
- 406 </style>
2. コードの初期値を知る
parent="@android:style/Widget.SeekBar" を外してみましょう。そうすると、バーの進み具合がつまみの中心になります。
このときは minHeight, maxHeight, thumbOffset は設定されていないわけですから、コード内で設定されていないときの初期値が割り当てられています。
SeekBar の親クラスの AbsSeekBar でその処理が実装されています。
tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/AbsSeekBar.java
- 65 public AbsSeekBar(Context context, AttributeSet attrs, int defStyle) {
- 66 super(context, attrs, defStyle);
- 67
- 68 TypedArray a = context.obtainStyledAttributes(attrs,
- 69 com.android.internal.R.styleable.SeekBar, defStyle, 0);
- 70 Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
- 71 setThumb(thumb); // will guess mThumbOffset if thumb != null...
- 72 // ...but allow layout to override this
- 73 int thumbOffset = a.getDimensionPixelOffset(
- 74 com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
- 75 setThumbOffset(thumbOffset);
- 76 a.recycle();
- 77
- 78 a = context.obtainStyledAttributes(attrs,
- 79 com.android.internal.R.styleable.Theme, 0, 0);
- 80 mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
- 81 a.recycle();
- 82
- 83 mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- 84 }
- 94 public void setThumb(Drawable thumb) {
- 95 boolean needUpdate;
- 96 // This way, calling setThumb again with the same bitmap will result in
- 97 // it recalcuating mThumbOffset (if for example it the bounds of the
- 98 // drawable changed)
- 99 if (mThumb != null && thumb != mThumb) {
- 100 mThumb.setCallback(null);
- 101 needUpdate = true;
- 102 } else {
- 103 needUpdate = false;
- 104 }
- 105 if (thumb != null) {
- 106 thumb.setCallback(this);
- 107
- 108 // Assuming the thumb drawable is symmetric, set the thumb offset
- 109 // such that the thumb will hang halfway off either edge of the
- 110 // progress bar.
- 111 mThumbOffset = thumb.getIntrinsicWidth() / 2;
- 112
- 113 // If we're updating get the new states
- 114 if (needUpdate &&
- 115 (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
- 116 || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
- 117 requestLayout();
- 118 }
- 119 }
- 120 mThumb = thumb;
- 121 invalidate();
- 122 if (needUpdate) {
- 123 updateThumbPos(getWidth(), getHeight());
- 124 if (thumb.isStateful()) {
- 125 // Note that if the states are different this won't work.
- 126 // For now, let's consider that an app bug.
- 127 int[] state = getDrawableState();
- 128 thumb.setState(state);
- 129 }
- 130 }
- 131 }
- 132
- 133 /**
- 134 * @see #setThumbOffset(int)
- 135 */
- 136 public int getThumbOffset() {
- 137 return mThumbOffset;
- 138 }
つまり、parent="@android:style/Widget.SeekBar" を入れていると、thumbOffset が 8dip なので、横幅が 16dip ではない画像をつまみとして使うとずれてしまうという事です。
3. padding をセットする
このままだと端にいったときにつまみが切れてしまいます。実は Holo テーマの SeekBar はその辺りの設定が正しくされています。
Holo テーマでの SeekBar の設定をみてみましょう。
- 1739 <style name="Widget.Holo.SeekBar">
- 1740 <item name="android:indeterminateOnly">false</item>
- 1741 <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
- 1742 <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
- 1743 <item name="android:minHeight">13dip</item>
- 1744 <item name="android:maxHeight">13dip</item>
- 1745 <item name="android:thumb">@android:drawable/scrubber_control_selector_holo</item>
- 1746 <item name="android:thumbOffset">16dip</item>
- 1747 <item name="android:focusable">true</item>
- 1748 <item name="android:paddingLeft">16dip</item>
- 1749 <item name="android:paddingRight">16dip</item>
- 1750 </style>
この設定によって、つまみが内側に収まるようにしているのです。
この padding に設定する値はつまみ画像の横幅の半分にします。
例えば、この星の画像は横幅が 68px で、xhdpi 用としているので、dip に直すと 68 / 2 = 34dip です。 横幅の半分を padding にするので 17dip です。
よって
- <style name="MySeekBar">
- <item name="android:indeterminateOnly">false</item>
- <item name="android:progressDrawable">@drawable/seekbar</item>
- <item name="android:indeterminateDrawable">@drawable/seekbar</item>
- <item name="android:thumb">@drawable/seekbar_thumb</item>
- <item name="android:paddingLeft">17dip</item>
- <item name="android:paddingRight">17dip</item>
- </style>
こうするとわかりますが、つまみの画像の横幅は 32dip (xhdpi 用だと 64px)がいいんでしょうね。
0 件のコメント:
コメントを投稿