如何判断多个getView结果中的哪一个可见?
我需要将自定义按钮对象添加到ListView中的每一行。这里有一个简单的行布局:如何判断多个getView结果中的哪一个可见?
<LinearLayout android:id="@+id/table_cell"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/label"
android:textSize="19dp"
android:textStyle="bold"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:lines="1"
/>
<LinearLayout android:id="@+id/button_wrapper"
android:layout_width="100dp"
android:layout_height="match_parent"
/>
</LinearLayout>
在我的自定义ArrayAdapter,我把按钮进入getView()电池:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// recycle the cell if possible
View cell = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cell = inflater.inflate(R.layout.table_cell, parent, false);
} else {
cell = convertView;
}
MyButton button = (MyButton) this.buttons.get(position);
if (button != null) {
// remove the button from the previous instance of this cell
ViewGroup parent = (ViewGroup)button.getParent();
if (parent != null) {
parent.removeView(button);
}
// add the button to the new instance of this cell
ViewGroup buttonWrapper = (ViewGroup)cell.findViewById(R.id.button_wrapper);
buttonWrapper.addView(button);
}
}
我知道getView()被调用多次为每个表当我滚动表格或单击按钮或做其他事情时,上面的代码会将按钮从前一个视图中删除,然后再将其添加到新视图中以避免“视图已有父项”异常。
的问题是,这是假定从getView生成的最新观点是,在屏幕上是可见的,但情况往往并非如此。有时getView()会生成新的视图,但屏幕上会保留一个较旧的视图。在这种情况下,我的按钮会消失,因为getView()会将其移动到不可见的新视图。我发现,行为通过初始化命名repeatRowTest
一个int变量,然后将里面getView()这样的代码:
if (position == 0) {
Log.d("getView", "repeat row count: " + repeatRowCountTest);
TextView label = (TextView)cell.findViewById(R.id.label);
label.setText(String.format("%d %s", repeatRowCountTest, label.getText()));
repeatRowCountTest++;
}
这说明我有多少次给定行已经生成,并实例当前显示。我可能会看到一行产生了10次,而仅显示了第5行。但是,如果显示行的最新实例,我的按钮才会显示。
所以,问题是,我怎么能告诉是否getView()实际上是将要显示的,所以我知道是否将我的按钮进去,还是离开我的按钮,它是产生一排?或者更一般地说,我怎么可以添加一个按钮到一行,并确保它保持可见,因为getView重复给定的位置?
我检查所显示的行的所有特性与一个额外的,不显示行,找不到任何差别。我也尝试在按钮消失后调用数组适配器上的notifyDataSetChanged,并使用包含按钮的所有最新视图刷新列表 - 但不清楚哪些事件触发getView重复自身,所以我不知道当我需要调用notifyDataSetChanged以使事情再次正确。我想我可以克隆按钮并为该行的每个新实例添加一个新的按钮实例,但似乎比必要的资源密集程度更高,并且会产生其他问题,因为其他对象具有对这些按钮的引用。我还没有找到任何代码示例显示了实现此目的的最佳方式,但它似乎是一个常见要求,所以希望我错过了一些简单的东西!
UPDATE:是否有一个ArrayAdapter我可以覆盖的getView()方法被调用后调用的方法?如果是这样,我可以检查所有最近创建的行的父项,以查看它们是否实际显示在ListView中,如果不是,则刷新ListView。
我注意到,如果我在问题发生后滚动ListView,所有行重新显示按钮,所以显然Android意图显示每行的最新视图,但它并不总是刷新视图。
然后我试图找出是什么导致getView重复运行的当前可见行(通常它只会在新行进入视图时运行)。不幸的是,在这个活动的其他地方发生的很多事情都是触发ListView来重新生成其视图,就像一个ProgressBar随着音频播放一样移动,一个动画缩短和延长ListView以显示旁边的另一个视图,而里面的按钮表格行使用不同的图形进行更新,以显示应用程序正在跟踪的不同事物的状态。我能够消除其中的一些,例如通过在更新其状态之前检查按钮是否已经处于期望的状态,但我无法消除所有这一切。
由于触发getView的最常见操作是更新音频ProgressBar,因此每次更新ProgressBar时我都会在ListView上添加一行以调用invalidateViews()。这使ListView刷新,以便最新的视图始终保持可见,因此我的视图始终保持可见。在调试器中运行时,会降低应用程序的运行速度,但在独立设备上运行时,性能变化不明显。
在这一点上问一个更好的问题可能是为什么与ListView无关的ProgressBar会导致ListView不断重新生成其视图。如果我有时间,或者遇到更多问题,我会将其作为一个单独的问题发布。
您不需要通过代码创建自定义按钮,您可以像插入普通的android按钮一样将其插入行布局xml中。通过这种方式,您可以从getView中删除按钮封装器布局和添加/删除逻辑。
<LinearLayout android:id="@+id/table_cell"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/label"
android:textSize="19dp"
android:textStyle="bold"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:lines="1"
/>
<yourpackagename.MyButton
android:id="@+id/button"
android:layout_width="100dp"
android:layout_height="match_parent"
/>
</LinearLayout>
用代码很容易理解,但也许你必须适应它。
XML:
<LinearLayout android:id="@+id/table_cell"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/label"
android:textSize="19dp"
android:textStyle="bold"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:lines="1"
/>
<yourpackagename.MyButton
android:id="@+id/button1"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button2"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button3"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button4"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button5"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button6"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button7"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
<yourpackagename.MyButton
android:id="@+id/button8"
android:layout_width="12dp"
android:layout_height="match_parent"
/>
</LinearLayout>
你传递给适配器
模型类:
public class MyRowModel
{
public boolean isButton1Visible;
public boolean isButton2Visible;
public boolean isButton3Visible;
public boolean isButton4Visible;
public boolean isButton5Visible;
public boolean isButton6Visible;
public boolean isButton7Visible;
public boolean isButton8Visible;
}
ViewHolder:
private class ViewHolder {
public MyButton b1;
public MyButton b2;
public MyButton b3;
public MyButton b4;
public MyButton b5;
public MyButton b6;
public MyButton b7;
public MyButton b8;
}
getView方法:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.table_cell, parent, false);
viewHolder = new ViewHolder();
viewHolder.b1 = (MyButton)convertView.findViewById(R.id.button1);
viewHolder.b2 = (MyButton)convertView.findViewById(R.id.button2);
viewHolder.b3 = (MyButton)convertView.findViewById(R.id.button3);
viewHolder.b4 = (MyButton)convertView.findViewById(R.id.button4);
viewHolder.b5 = (MyButton)convertView.findViewById(R.id.button5);
viewHolder.b6 = (MyButton)convertView.findViewById(R.id.button6);
viewHolder.b7 = (MyButton)convertView.findViewById(R.id.button7);
viewHolder.b8 = (MyButton)convertView.findViewById(R.id.button8);
convertView.setTag(viewHolder);
} else {
viewHolder = convertView.getTag();
}
MyRowModel myRowModel = getItem(position);
if(myRowModel.isButton1Visible)
{
viewHolder.b1.setVisibility(View.VISIBLE);
}
else
{
viewHolder.b1.setVisibility(View.INVISIBLE);
}
if(myRowModel.isButton2Visible)
{
viewHolder.b2.setVisibility(View.VISIBLE);
}
else
{
viewHolder.b2.setVisibility(View.INVISIBLE);
}
//and so on
return convertView;
}
你是在暗示这是解决我的问题,还是只是一种重组我的代码的方法?我在getView中需要一些条件逻辑,因为并不是所有的表行都需要按钮。 – arlomedia 2014-11-05 09:23:01
在这种情况下,检查这个http://*.com/questions/4777272/android-listview-with-different-layout-for-each-row – 2014-11-05 09:26:41
行实际上最多包含八个不同组合的按钮,所以它不会'为每个按钮组合设置不同的XML布局是切实可行的。我想我可以在XML中包含所有按钮,并根据需要从代码中隐藏/显示它们。你是否暗示我的问题可以通过在XML中定义我的按钮来解决?那会为表格行的每个新实例创建一个新的按钮实例吗? – arlomedia 2014-11-05 09:48:04
只需在一行或两行清除您的需求。 – 2014-11-05 09:15:20