Android 開發 Tip 6 -- Spinner

來源:互聯網
上載者:User

標籤: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 適配器 。還有兩個重要的布局檔案:

  • simple_spinner_item

  • simple_spinner_dropdown_item

子類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設定了 directiontextAligment 兩個屬性!!!

Android 開發 Tip 6 -- Spinner

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.