【问题标题】:Set spinner width to current item width将微调器宽度设置为当前项目宽度
【发布时间】:2017-02-21 22:12:58
【问题描述】:

默认情况下,微调器宽度设置为适合下拉列表中最大的项目,但我希望它与所选项目的宽度相同。

<android.widget.Spinner
    android:id="@+id/tab_spinner"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:entries="@array/countries" />

正如您在右侧图片中看到的那样,微调器太长了,因为列表中的项目很长。

如何将其调整为所选项目的宽度?

【问题讨论】:

    标签: android width spinner selection


    【解决方案1】:

    默认情况下,Spinner 将尝试测量您的一些下拉视图并使用找到的最大宽度。这发生在Spinner#measureContentWidth() 中,Spinnerprotected 方法在Spinner#onMeasure() 中调用。

    解决此问题的一种方法是确保您的 SpinnerAdapter#getView() 方法始终使用 Spinner#getSelectedItemPosition() 作为其 position 参数。

    我能想到两种可能的解决方案:

    1. 使用包装适配器创建自定义微调器(我更喜欢这种解决方案)
    2. 或调整您的自定义适配器


    1.使用包装适配器创建自定义微调器

    确保在您的 xml 布局中使用它,而不是普通的 &lt;Spinner&gt;

    注意DynamicWidthSpinner#getAdapter() 将返回WrapperSpinnerAdapter;使用其getBaseAdapter() 方法访问您的适配器。

    public class DynamicWidthSpinner extends Spinner {
    
        public DynamicWidthSpinner(Context context) {
            super(context);
        }
    
        public DynamicWidthSpinner(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public DynamicWidthSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
    
        public void setAdapter(SpinnerAdapter adapter) {
            super.setAdapter(adapter != null ? new WrapperSpinnerAdapter(adapter) : null);
        }
    
    
        public final class WrapperSpinnerAdapter implements SpinnerAdapter {
    
            private final SpinnerAdapter mBaseAdapter;
    
    
            public WrapperSpinnerAdapter(SpinnerAdapter baseAdapter) {
                mBaseAdapter = baseAdapter;
            }
    
    
            public View getView(int position, View convertView, ViewGroup parent) {
                return mBaseAdapter.getView(getSelectedItemPosition(), convertView, parent);
            }
    
            public final SpinnerAdapter getBaseAdapter() {
                return mBaseAdapter;
            }
    
            public int getCount() {
                return mBaseAdapter.getCount();
            }
    
            public View getDropDownView(int position, View convertView, ViewGroup parent) {
                return mBaseAdapter.getDropDownView(position, convertView, parent);
            }
    
            public Object getItem(int position) {
                return mBaseAdapter.getItem(position);
            }
    
            public long getItemId(int position) {
                return mBaseAdapter.getItemId(position);
            }
    
            public int getItemViewType(int position) {
                return mBaseAdapter.getItemViewType(position);
            }
    
            public int getViewTypeCount() {
                return mBaseAdapter.getViewTypeCount();
            }
    
            public boolean hasStableIds() {
                return mBaseAdapter.hasStableIds();
            }
    
            public boolean isEmpty() {
                return mBaseAdapter.isEmpty();
            }
    
            public void registerDataSetObserver(DataSetObserver observer) {
                mBaseAdapter.registerDataSetObserver(observer);
            }
    
            public void unregisterDataSetObserver(DataSetObserver observer) {
                mBaseAdapter.unregisterDataSetObserver(observer);
            }
        }
    }
    


    2.调整您的自定义适配器

    注意getView() 中的parent 可能并不总是Spinner

    private class SimpleSpinnerAdapter extends BaseAdapter {
    
        private LayoutInflater mInflater;
        private int mResource;
    
    
        public SimpleSpinnerAdapter(Context context, int resource) {
            mInflater = LayoutInflater.from(context);
            mResource = resource;
        }
    
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return createViewFromResource(
                    mInflater,
                    ((Spinner) parent).getSelectedItemPosition(),
                    convertView,
                    parent,
                    mResource);
        }
    
        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            return createViewFromResource(
                    mInflater,
                    position,
                    convertView,
                    parent,
                    mResource);
        }
    
        protected View createViewFromResource(LayoutInflater inflater, int position, 
                                              View convertView, ViewGroup parent,
                                              int resource) {
            View view;
            if (convertView == null) {
                view = inflater.inflate(resource, parent, false);
            } else {
                view = convertView;
            }
    
            bindView(position, view);
    
            return view;
        }
    
        protected void bindView(int position, View view) {
            // Bind your view.
        }
    
        // getCount(), getItem(), and getItemId() methods.
    }
    

    【讨论】:

    • 第一个选项是最灵活的一个
    • 第一个选项对我不起作用。当我实现它时(我不得不针对 kotlin 和 getView 函数中的缺失代码对其进行调整)微调器不响应点击事件并且下拉箭头消失了。我将把我当前的代码放在下面的回复中。我正在使用自定义 TextView 作为微调器项
    • @jpmcosta 我把我的代码放在一个新的 SO 问题中:stackoverflow.com/questions/56998198/…
    【解决方案2】:
      ViewGroup.LayoutParams spinnerLayoutParams = spinner.getLayoutParams();
        spinnerLayoutParams.width -= 1;
       spinner.setLayoutParams(spinnerLayoutParams);
    

    在所选项目上执行此操作

    【讨论】:

    • 值“-1”是 MATCH_PARENT 。为什么会有帮助?
    【解决方案3】:

    将微调器 XML 设置为:

    android:layout_width="wrap_content"
    

    为我工作。

    【讨论】:

    • 抱歉忘记发布我的代码,但它已经是这样了,对我没有任何改变......
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多