从最近几天开始,我试图让Spinner在ViewGroup中工作,但没有任何成功。 : - {。 在自定义ViewGroup里面我放置了片段容器。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:boxMenu="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestActivity"
android:id="@+id/frame" >
<com.imper.boxmenulibrary.BoxMenuLayout
android:id="@+id/box_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
boxMenu:boxSize="40dp"
boxMenu:directionY="bottomToTop"
boxMenu:directionX="rightToLeft"
boxMenu:showStart="false"
android:padding="5dp"
android:background="#ffffff00">
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:orientation="vertical">
</LinearLayout>
</com.imper.boxmenulibrary.BoxMenuLayout>
在那个片段容器中我替换像这样的片段:
FragmentManager fm = ((Activity) context).getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_container, new TestFragment());
ft.commit();
我的TestFragment xml布局如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Spinner
android:id="@+id/test_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
TestFragment实现如下:
public class TestFragment extends BoxLayout implements OnItemSelectedListener {
Spinner testSpinner;
public TestFragment() {}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
View view = inflater.inflate(R.layout.test_view, container, false);
testSpinner = (Spinner) view.findViewById(R.id.test_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(container.getContext(), R.array.day, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
testSpinner.setAdapter(adapter);
testSpinner.setOnItemSelectedListener(this);
return view;
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Toast.makeText(getActivity(), "Bingo", Toast.LENGTH_SHORT).show();
Log.d("Bingo", "onItemSelected");
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
Toast.makeText(getActivity(), "Bingo Nothing", Toast.LENGTH_SHORT).show();
Log.d("Bingo", "onNothingSelected");
}
}
现在,问题是当我试图从Spinner下拉选择某些内容时,没有选择任何内容,OnItemSelected事件根本不会被触发。
当FragmentContainer从我的自定义ViewGroup移出时,相同的代码工作正常。 为什么会这样?如何让Spinner在自定义视图组中正常工作?
答案 0 :(得分:2)
第二次编辑--------------
我遇到了与你非常相似的问题。 (有关更多详细信息,请参阅下面的原始帖子。)如果不了解有关自定义ViewGroup实现的更多信息,我不知道我的解决方案是否适合您。
我的问题结果是在我的“layoutChildren”实现中我引入了一个“优化”,如果我重用一个子视图,我知道它的内容没有改变(并且布局窗口也没有改变)我没有费心去重新测量孩子的观点。
事实证明,如果你使用Spinners,你就无法逃避这一点。原因与某些View.mPrivateFlags(PFLAGS_FORCE_LAYOUT和PFLAGS_LAYOUT_REQUIRED)相对于跟踪重新处理子视图布局的需要实现了错综复杂的方式IN COMBINATION与Spinner决定触发onItemSelected侦听器的方式。
如下所述,Spinner在要求执行布局时触发onItemSelected侦听器,并在其中识别所选项目已更改。如果它不执行布局,它(内部)知道所选项已更改,但不会调用onItemSelected侦听器。
从Spinner的角度来看,这没关系,因为当Spinner看到新项目被选中时,它特意请求了布局传递(requestLayout)。
布局传递开始并向下传播到我的自定义ViewGroup。当它到达第一个子节点时,子节点的PFLAGS_FORCE_LAYOUT位置位......但处理逻辑忽略该标志。相反,它只查找PFLAGS_LAYOUT_REQUIRED位,当它没有看到该标志时,它决定没有必要在视图层次结构中向下传播布局,因此Spinner永远不会被要求执行布局而永远不会触发onItemSelected侦听器。
修复方法是删除优化以不测量尺寸已知的子视图。 PFLAGS_LAYOUT_REQUIRED(包私有......你无法从你写的任何内容中获取)仅在要求子视图自我测量时才设置,即使测量本身在我的情况下不是绝对必要的,它也是将mPrivateFlags操纵到正确状态的唯一方法。
检查以确定您正在衡量您的子视图(特别是从之前的布局过程中重复使用的视图),看看这是否解决了您的问题。
首先编辑---------------
我在这方面取得了一些进展,但仍未解决。 Spinner在调用onLayout()方法时调用onItemSelected侦听器,并且它识别出所选项已更改。
当Spinner由ListView托管时,ListView.onLayout(...)在Spinner中的选择被更改后被调用(虽然我无法弄清楚如何),以及ListView onLayout方法传播调用Spinner,导致onItemSelected()调用。
当我的自定义AdapterView托管Spinner时,在Spinner更改后永远不会调用onLayout方法,因此不会进行onItemSelected()调用。
我还没有弄清楚在一种情况下触发布局请求的原因,地点或方式,而不是另一种情况。因为布局请求被发布到消息队列并从那里执行,所以很难确定它的来源。
请告诉我这是否对您有所帮助,或者给您任何想法。
Original Post ------------
我遇到了同样的问题。我创建了一个自定义ViewGroup(扩展的AdapterView),现在包含微调器的子视图不会触发onItemSelected侦听器。如果我将相同的子视图附加到ListView(也从AdapterView扩展),它工作正常。我在自定义ViewGroup中做错了什么,但我不知道是什么。
您找到了问题的解决方案吗?如果是这样,你可以发布吗?
答案 1 :(得分:0)
这篇文章非常陈旧,但它给了我很大的帮助 - 虽然我仍然遇到了问题(尽管我每次都从下拉列表中选择一些东西 - 而不是每次都这样)。
如果有帮助 - 我的问题的解决方法是不在显示问题的微调器对象上调用bringToFront。
答案 2 :(得分:0)
正如史蒂夫已经指出的那样,问题是需要操纵某些标志来实际强制布局,而这样做的唯一(公共)方式是调用measure()......
作为一种解决方法,将以下方法添加到我的自定义ViewGroup可以解决我的问题,但您可能需要确保不要进行太多额外/冗余测量,具体取决于实际用例......
public void requestLayout() {
super.requestLayout();
measure(MeasureSpec.EXACTLY | getMeasuredWidth(),
MeasureSpec.EXACTLY | getMeasuredHeight());
}
重现问题的最小代码段:
package org.kobjects.spinnertestapp;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import java.util.ArrayList;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> options = new ArrayList<>();
options.add("Hello");
options.add("Wutan");
options.add("Lorem Ipsum");
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this,android.R.layout.simple_spinner_dropdown_item, options);
Spinner spinner = new Spinner(this);
spinner.setAdapter(arrayAdapter);
MyLayout layout = new MyLayout(this);
layout.addView(spinner);
setContentView(layout);
}
static class MyLayout extends ViewGroup {
public MyLayout(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
for (int i = 0; i < getChildCount(); i ++) {
getChildAt(i).layout(left, top, right, bottom);
}
}
}
}