標籤:position .net super layout turn extends markdown esc 跟蹤
轉載請註明出處:http://blog.csdn.net/crazy1235/article/details/70903974
設定Spinner 文字置中
預設情況下,Spinner控制項的效果是這樣的:
想讓文字置中顯示怎麼辦???
在布局檔案中設定
android:gravity="center"
也不起作用!!
源碼走讀
先來看 Spinner 的建構函式
public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode, Theme popupTheme) { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.Spinner, defStyleAttr, defStyleRes); // 省略代碼 if (mode == MODE_THEME) { mode = a.getInt(R.styleable.Spinner_spinnerMode, MODE_DIALOG); } // 判斷彈出模式 dialog or dropdown switch (mode) { case MODE_DIALOG: { mPopup = new DialogPopup(); // DialogPopup mPopup.setPromptText(a.getString(R.styleable.Spinner_prompt)); break; } case MODE_DROPDOWN: { final DropdownPopup popup = new DropdownPopup( mPopupContext, attrs, defStyleAttr, defStyleRes); // DropdownPopup // 省略代碼 break; } } // ... a.recycle(); // 設定adapter if (mTempAdapter != null) { setAdapter(mTempAdapter); mTempAdapter = null; } }
當mTempAdapter 不為空白時,調用了setAdapter() 設定適配器!
但是我們如果在xml中設定了entries屬性,並沒有設定adapter
android:entries="@array/date_spinner_items"
的列表是怎麼出來的呢?!
來看父類~~
AbsSpinner
public AbsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initAbsSpinner(); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes); final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries); if (entries != null) { final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( context, R.layout.simple_spinner_item, entries); adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item); setAdapter(adapter); } a.recycle(); }
從構造器函數中看出,當entries屬性不為空白時,調用了 setAdapter() 函數!
注意這裡,用到的是 ArrayAdapter 適配器 。還有兩個重要的布局檔案:
子類Spinner重寫了setAdapter 函數
@Override public void setAdapter(SpinnerAdapter adapter) { // ... super.setAdapter(adapter); // ... mPopup.setAdapter(new DropDownAdapter(adapter, popupContext.getTheme())); }
mPopup 是一個介面對象,裡面封裝了 設定適配器、顯示列表、關閉列表等操作!
不管是Spinner是 dialog 形式還是 dropdown 形式,都實現了該介面!
private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener
private class DropdownPopup extends ListPopupWindow implements SpinnerPopup
OK,現在來看 DropDownAdapter
private static class DropDownAdapter implements ListAdapter, SpinnerAdapter { private SpinnerAdapter mAdapter; private ListAdapter mListAdapter; public DropDownAdapter(@Nullable SpinnerAdapter adapter, @Nullable Resources.Theme dropDownTheme) { mAdapter = adapter; // 注意這裡!!! // 省略代嗎 } public int getCount() { return mAdapter == null ? 0 : mAdapter.getCount(); } public Object getItem(int position) { return mAdapter == null ? null : mAdapter.getItem(position); } public long getItemId(int position) { return mAdapter == null ? -1 : mAdapter.getItemId(position); } public View getView(int position, View convertView, ViewGroup parent) { return getDropDownView(position, convertView, parent); } public View getDropDownView(int position, View convertView, ViewGroup parent) { return (mAdapter == null) ? null : mAdapter.getDropDownView(position, convertView, parent); } // 省略代嗎 }
彈出來的列表每個item的View渲染通過 getDropDownView 函數!
而mAdapter是通過建構函式傳進來的!
再回到這裡:
mPopup.setAdapter(new DropDownAdapter(adapter, popupContext.getTheme()));
這時adapter是Spinner父類AbsSpinner建構函式中new出來的 ArrayAdapter
然後看 ArrayAdapter 類中的 getDropDownView 函數
@Override public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater; return createViewFromResource(inflater, position, convertView, parent, mDropDownResource); }
private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position, @Nullable View convertView, @NonNull ViewGroup parent, int resource) { final View view; final TextView text; if (convertView == null) { view = inflater.inflate(resource, parent, false); } else { view = convertView; } try { if (mFieldId == 0) { text = (TextView) view; } else { text = (TextView) view.findViewById(mFieldId); if (text == null) { throw new RuntimeException("Failed to find view with ID " + mContext.getResources().getResourceName(mFieldId) + " in item layout"); } } } catch (ClassCastException e) { Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); throw new IllegalStateException( "ArrayAdapter requires the resource ID to be a TextView", e); } // 省略代碼!!! return view; }
源碼看到這裡就能發現,通過映射 mDropDownResource這個布局檔案,來得到Spinner列表的item布局!
而,恰恰在AbsSpinner 的建構函式中設定了這一布局檔案
adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
所以,現在想要改變Spinner的文字置中顯示!則需要設定相應的adapter!
OK。現在就來看這個布局檔案
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" style="?android:attr/spinnerDropDownItemStyle" android:singleLine="true" android:layout_width="match_parent" android:layout_height="?android:attr/dropdownListPreferredItemHeight" android:ellipsize="marquee"/>
可以看出item布局檔案只是一個 CheckedTextView
我們現在想要把這個列表的文字置中顯示!
跟蹤style檔案發現設定的gravity屬性是 center_vertical
<item name="android:gravity">center_vertical</item>
此時嘗試把這個布局檔案拿出來重寫。
simple_spinner_dropdown_item.xml
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" style="?android:attr/spinnerDropDownItemStyle" android:layout_width="match_parent" android:layout_height="?attr/listPreferredItemHeightSmall" android:ellipsize="marquee" android:gravity="center" // !!! android:maxLines="1" />
然後在Activity中對Spinner對象設定適配器!
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, dates);arrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);spinner.setAdapter(arrayAdapter);
運行之後,發現並沒有置中!
現在,回過頭來看看 mPopup.show() 顯示列表的函數
加入我們選擇的是dropdown模式!
DropdownPopup.show()
public void show(int textDirection, int textAlignment) { final boolean wasShowing = isShowing(); computeContentWidth(); setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); super.show(); final ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setTextDirection(textDirection); listView.setTextAlignment(textAlignment); setSelection(Spinner.this.getSelectedItemPosition()); // ... 省略代碼 }
可以看出,彈出來的視圖就是一個ListView
針對listview設定了 direction 和 textAligment 兩個屬性!!!
Android 開發 Tip 6 -- Spinner