我想知道为什么要使用ListView的layout_height =" wrap_content"在列表的末尾弄乱了Spinners。我在下面尝试了不同的修复方法。我希望有人可以解释这个行为,或者指出我在绘制视图/ ui事件时缺乏的知识。
1)可以看到问题here。
2)更改ListItem属性后
android:descendantFocusability="afterDescendants"
我的行为更好但有些事情仍在继续。看起来列表中的项目似乎没有收到事件,因此属性更改对我来说很有意义。 Here is a video更新该属性后微调器的行为方式。 一切正常,除非我实际选择了一个项目。
3)设置ListView的layout_height =" match_parent"选择一个项目后问题似乎消失了。该视频See here。
活动:
public class SelectorActivity extends Activity {
public static final String TAG = SelectorActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
setContentView(R.layout.activity_selector);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView contents = (ListView) findViewById(R.id.list_view);
contents.addHeaderView(new TestView(this));
contents.addFooterView(new View(this));
SimpleBaseAdapter listAdapter = new SimpleBaseAdapter(this);
// LOW RANGE
LinearLayout lowRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView lowRangeText = (TextView) lowRange.findViewById(R.id.text);
EditText lowRangeEditText = (EditText) lowRange.findViewById(android.R.id.edit);
// HIGH RANGE
LinearLayout highRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView highRangeText = (TextView) highRange.findViewById(R.id.text);
EditText highRangeEditText = (EditText) highRange.findViewById(android.R.id.edit);
// UNITS
LinearLayout units = (LinearLayout) inflater.inflate(R.layout.list_item_units, null);
TextView unitsText = (TextView) units.findViewById(android.R.id.text1);
// SPINNERS
LinearLayout spinners = (LinearLayout) inflater.inflate(R.layout.list_item_spinners, null);
Spinner spinner1 = (Spinner) spinners.findViewById(R.id.spinner1);
Spinner spinner2 = (Spinner) spinners.findViewById(R.id.spinner2);
Spinner spinner3 = (Spinner) spinners.findViewById(R.id.spinner3);
DebugAdapterViewListeners.set(spinner1, "spinner1");
// VIEW SETUP
lowRangeText.setText("text1");
highRangeText.setText("text2");
unitsText.setText("text3");
// SPINNER SETUP
String[] massUnits1 = new String[]{"one","two"};
String[] massUnits2 = new String[]{"three","four"};
String[] timeUnits = new String[]{"five","six"};
ArrayAdapter<String> adapt1 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt2 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt3 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
adapt1.addAll(massUnits1);
adapt2.addAll(massUnits2);
adapt3.addAll(timeUnits);
spinner1.setAdapter(adapt1);
spinner2.setAdapter(adapt2);
spinner3.setAdapter(adapt3);
listAdapter.addView(lowRange);
listAdapter.addView(highRange);
listAdapter.addView(units);
listAdapter.addView(spinners);
contents.setAdapter(listAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.selector, menu);
return false;
}
}
这是SimpleBaseAdapter类:
public class SimpleBaseAdapter extends BaseAdapter {
private ArrayList<View> views;
private Context context;
public SimpleBaseAdapter(Context context) {
this.context = context;
this.views = new ArrayList<View>();
}
public void addView(View view) {
this.views.add(view);
}
@Override
public int getCount() {
return views.size();
}
@Override
public Object getItem(int position) {
View view = views.get(position);
if (view instanceof AbsListView) {
return ((AbsListView)view).getItemAtPosition(position);
} else if (view instanceof AbsSpinner) {
return ((AbsSpinner)view).getItemAtPosition(position);
} else {
return null;
}
}
@Override
public long getItemId(int position) {
View view = views.get(position);
if (view instanceof AbsListView) {
return ((AbsListView)view).getItemIdAtPosition(position);
} else if (view instanceof AbsSpinner) {
return ((AbsSpinner)view).getItemIdAtPosition(position);
} else {
return 0;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return views.get(position);
}
}
活动布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/green_1"
android:orientation="vertical"
>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:headerDividersEnabled="true"
android:footerDividersEnabled="true"
android:dividerHeight="0.5sp"
android:divider="@color/black"
android:clipToPadding="false"
android:layout_marginTop="18sp"
android:layout_marginBottom="18sp"
/>
</LinearLayout>
编辑列表项布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="@dimen/row_padding"
android:background="@android:color/white"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text"
android:layout_weight="50"
android:gravity="top"
android:textSize="@dimen/font_size_standard"
android:textColor="@drawable/selector_row_item_detail_text"
/>
<EditText
android:layout_width="0dip"
android:layout_height="wrap_content"
android:id="@android:id/edit"
android:layout_weight="50"
android:inputType="number"
android:gravity="right"
/>
</LinearLayout>
微调器行项目布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/spinner_container"
android:orientation="horizontal"
android:background="@android:color/white"
android:paddingTop="@dimen/header_row_padding_vertical"
>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner1"
android:gravity="center"
android:spinnerMode="dropdown"
/>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner2"
android:gravity="center"
android:spinnerMode="dialog"
/>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner3"
android:gravity="center"
android:spinnerMode="dialog"
/>
</LinearLayout>
答案 0 :(得分:4)
您遇到的问题是Spinner的基本行为,因此需要修改Spinner。这是微调器的代码,其初始即为。默认情况下,可视化是“选择项目”(如果在.xml中声明的提示,如android:prompt="@string/Select Item"
)&amp;下拉视图与原始微调器的大小相同。此修改后的微调器的限制是,如果项目为空,则不显示提示。
创建一个名为NoDefaultSpinner.java
&amp;的新班级在该副本中粘贴此代码
public class NoDefaultSpinner extends Spinner {
public NoDefaultSpinner(Context context) {
super(context);
}
public NoDefaultSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(SpinnerAdapter orig ) {
final SpinnerAdapter adapter = newProxy(orig);
super.setAdapter(adapter);
try {
final Method m = AdapterView.class.getDeclaredMethod(
"setNextSelectedPositionInt",int.class);
m.setAccessible(true);
m.invoke(this,-1);
final Method n = AdapterView.class.getDeclaredMethod(
"setSelectedPositionInt",int.class);
n.setAccessible(true);
n.invoke(this,-1);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
new Class[]{SpinnerAdapter.class},
new SpinnerAdapterProxy(obj));
}
/**
* Intercepts getView() to display the prompt if position < 0
*/
protected class SpinnerAdapterProxy implements InvocationHandler {
protected SpinnerAdapter obj;
protected Method getView;
protected SpinnerAdapterProxy(SpinnerAdapter obj) {
this.obj = obj;
try {
this.getView = SpinnerAdapter.class.getMethod(
"getView",int.class,View.class,ViewGroup.class);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
return m.equals(getView) &&
(Integer)(args[0])<0 ?
getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) :
m.invoke(obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
protected View getView(int position, View convertView, ViewGroup parent)
throws IllegalAccessException {
if( position<0 ) {
final TextView v =
(TextView) ((LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE)).inflate(
android.R.layout.simple_spinner_item,parent,false);
v.setText(getPrompt());
return v;
}
return obj.getView(position,convertView,parent);
}
}
}
在微调器行项目布局中,将微调器的类型更改为<com.example.appname.NoDefaultSpinner
,如下所示
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner1"
android:gravity="center"
android:spinnerMode="dropdown"
/>
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner2"
android:gravity="center"
android:spinnerMode="dialog"
/>
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="@+id/spinner3"
android:gravity="center"
android:spinnerMode="dialog"
/>
活动:将Spinner的类型更改为NoDefaultSpinner,如下所示
public class SelectorActivity extends Activity {
public static final String TAG = SelectorActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
setContentView(R.layout.activity_selector);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView contents = (ListView) findViewById(R.id.list_view);
contents.addHeaderView(new TestView(this));
contents.addFooterView(new View(this));
SimpleBaseAdapter listAdapter = new SimpleBaseAdapter(this);
// LOW RANGE
LinearLayout lowRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView lowRangeText = (TextView) lowRange.findViewById(R.id.text);
EditText lowRangeEditText = (EditText) lowRange.findViewById(android.R.id.edit);
// HIGH RANGE
LinearLayout highRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView highRangeText = (TextView) highRange.findViewById(R.id.text);
EditText highRangeEditText = (EditText) highRange.findViewById(android.R.id.edit);
// UNITS
LinearLayout units = (LinearLayout) inflater.inflate(R.layout.list_item_units, null);
TextView unitsText = (TextView) units.findViewById(android.R.id.text1);
// SPINNERS
LinearLayout spinners = (LinearLayout) inflater.inflate(R.layout.list_item_spinners, null);
NoDefaultSpinner spinner1 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner1);
NoDefaultSpinner spinner2 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner2);
NoDefaultSpinner spinner3 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner3);
DebugAdapterViewListeners.set(spinner1, "spinner1");
// VIEW SETUP
lowRangeText.setText("text1");
highRangeText.setText("text2");
unitsText.setText("text3");
// SPINNER SETUP
String[] massUnits1 = new String[]{"one","two"};
String[] massUnits2 = new String[]{"three","four"};
String[] timeUnits = new String[]{"five","six"};
ArrayAdapter<String> adapt1 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt2 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt3 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
adapt1.addAll(massUnits1);
adapt2.addAll(massUnits2);
adapt3.addAll(timeUnits);
spinner1.setAdapter(adapt1);
spinner2.setAdapter(adapt2);
spinner3.setAdapter(adapt3);
listAdapter.addView(lowRange);
listAdapter.addView(highRange);
listAdapter.addView(units);
listAdapter.addView(spinners);
contents.setAdapter(listAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.selector, menu);
return false;
}
此解决方案依赖于反射来调用AdapterView.setNextSelectedPositionInt()
和AdapterView.setSelectedPositionInt()
,&amp;在API 4上成功运行到API 19。
答案 1 :(得分:1)
您应该扩展SpinnerAdapter而不是BaseAdapter。它有getDropdownView()以及getView(),我相信它本身可以处理一些特殊情况。我在Android 4.2上以类似的布局扩展了这个适配器,我没有看到你遇到的问题。
我认为getDropdownView()处理如何将视图附加到根目录的差异会导致这种差异,但我还没有查看代码来检查这个