问题
遇到一个spinner 背景的问题,记录一下.
我在xml中定义了一个spinner
android:id="@+id/tracking_mode_spinner"
android:layout_width="wrap_content"
android:layout_height="33dp"
android:spinnerMode="dropdown"
android:background="@drawable/corner_white_bg_nor"
android:popupBackground="@drawable/spinner_pop_bg"/>
在java中调用:
mSpinner = findViewById(R.id.layout_spinner);
mSpinner.setDropDownVerticalOffset(mContext.getResources()
.getDimensionPixelSize(R.dimen.spinner_offset));
mSpinner.setDropDownWidth(mContext.getResources()
.getDimensionPixelSize(R.dimen.spinner_width));
mSpinner.setAnimation(null);
SpinnerAdapter adapter = SpinnerAdapter.createFromResource(mContext,
CameraFramingMode.createFramingModeEntries(true, false), R.layout.layout_spinner_pop_selectable_item);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
adapter.setSelectedPosition(position);
updateView();
}
@Override
public void onNothingSelected(AdapterView> parent) {
}
});
adapter 是这样使用:
SpinnerAdapter adapter = SpinnerAdapter.createFromResource(mContext,
CameraFramingMode.createFramingModeEntries(true, false), R.layout.layout_spinner_pop_selectable_item);
SpinnerAdapter 定义成这个
public static class SpinnerAdapter extends ArrayAdapter {
private int selectedPosition;
void setSelectedPosition(int selectedPosition) {
this.selectedPosition = selectedPosition;
}
SpinnerAdapter(@NonNull Context context, int resource, @NonNull T[] objects) {
super(context, resource, R.id.text, objects);
}
@Override
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View view = super.getDropDownView(position, convertView, parent);
TextView icon = view.findViewById(R.id.icon);
if (selectedPosition == position) {
FontsUtils.setTypeface(icon);
icon.setText(FontIcons.OK);
icon.setVisibility(View.VISIBLE);
} else {
icon.setVisibility(View.INVISIBLE);
}
return view;
}
static @NonNull
SpinnerAdapter createFromResource(@NonNull Context context,
CharSequence[] items, @LayoutRes int textViewResId) {
return new SpinnerAdapter<>(context, textViewResId, items);
}
}
layout_spinner_pop_selectable_item.xml
但是我发现spinner 设置的bg会被item的bg覆盖selector_spinner_item_bg.
抓取控件树发现,spinner的显示会把下拉框一个item作为显示的内容.
这样子会有问题,当item的布局样式和spinner不一样时,spinner的样式会被覆盖.
举个例子:当item背景要红色,spinner背景要黑色时,spinner设置了黑色背景无用.
原因
spinner源码中:makeView 获取view是通过Adapter#getView的方式获取的
/**
* Obtain a view, either by pulling an existing view from the recycler or
* by getting a new one from the adapter. If we are animating, make sure
* there is enough information in the view's layout parameters to animate
* from the old to new positions.
*
* @param position Position in the spinner for the view to obtain
* @param addChild true to add the child to the spinner, false to obtain and configure only.
* @return A view for the given position
*/
private View makeView(int position, boolean addChild) {
View child;
if (!mDataChanged) {
child = mRecycler.get(position);
if (child != null) {
// Position the view
setUpChild(child, addChild);
return child;
}
}
// Nothing found in the recycler -- ask the adapter for a view
child = mAdapter.getView(position, null, this);
// Position the view
setUpChild(child, addChild);
return child;
}
DropDownAdapter#getView,这个方法不是抽象,所以当我们没有重写此方法时,他返回的就是item的view.
public View getView(int position, View convertView, ViewGroup parent) {
return getDropDownView(position, convertView, parent);
}
修改
知道原因了就好修改了,我们重写getView重新设置一个view即可.