如何判断多个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。

+0

只需在一行或两行清除您的需求。 – 2014-11-05 09:15:20

我注意到,如果我在问题发生后滚动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; 
} 
+0

你是在暗示这是解决我的问题,还是只是一种重组我的代码的方法?我在getView中需要一些条件逻辑,因为并不是所有的表行都需要按钮。 – arlomedia 2014-11-05 09:23:01

+0

在这种情况下,检查这个http://*.com/questions/4777272/android-listview-with-different-layout-for-each-row – 2014-11-05 09:26:41

+0

行实际上最多包含八个不同组合的按钮,所以它不会'为每个按钮组合设置不同的XML布局是切实可行的。我想我可以在XML中包含所有按钮,并根据需要从代码中隐藏/显示它们。你是否暗示我的问题可以通过在XML中定义我的按钮来解决?那会为表格行的每个新实例创建一个新的按钮实例吗? – arlomedia 2014-11-05 09:48:04