2014-11-05 65 views
0

我需要將自定義按鈕對象添加到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

回答

0

我注意到,如果我在問題發生後滾動ListView,所有行重新顯示按鈕,所以顯然Android意圖顯示每行的最新視圖,但它並不總是刷新視圖。

然後我試圖找出是什麼導致getView重複運行的當前可見行(通常它只會在新行進入視圖時運行)。不幸的是,在這個活動的其他地方發生的很多事情都是觸發ListView來重新生成其視圖,就像一個ProgressBar隨着音頻播放一樣移動,一個動畫縮短和延長ListView以顯示旁邊的另一個視圖,而裏面的按鈕表格行使用不同的圖形進行更新,以顯示應用程序正在跟蹤的不同事物的狀態。我能夠消除其中的一些,例如通過在更新其狀態之前檢查按鈕是否已經處於期望的狀態,但我無法消除所有這一切。

由於觸發getView的最常見操作是更新音頻ProgressBar,因此每次更新ProgressBar時我都會在ListView上添加一行以調用invalidateViews()。這使ListView刷新,以便最新的視圖始終保持可見,因此我的視圖始終保持可見。在調試器中運行時,會降低應用程序的運行速度,但在獨立設備上運行時,性能變化不明顯。

在這一點上問一個更好的問題可能是爲什麼與ListView無關的ProgressBar會導致ListView不斷重新生成其視圖。如果我有時間,或者遇到更多問題,我會將其作爲一個單獨的問題發佈。

0

您不需要通過代碼創建自定義按鈕,您可以像插入普通的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://stackoverflow.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

相關問題