2011-01-23 37 views
318

Tôi đang cố gắng xác định cách tốt nhất để có một ListView duy nhất chứa các bố cục khác nhau cho mỗi hàng. Tôi biết làm thế nào để tạo một hàng tùy chỉnh + adapter mảng tùy chỉnh để hỗ trợ một hàng tùy chỉnh cho toàn bộ danh sách xem, nhưng làm thế nào tôi có thể thực hiện nhiều kiểu hàng khác nhau trong ListView?Android ListView với các bố trí khác nhau cho mỗi hàng

+1

này: Demo cho Nhiều bố trí hàng sử dụng android của RecyclerView http : //code2concept.blogspot.in/2015/10/android-multiple-row-layout-using.html – nitesh

Trả lời

399

Vì bạn biết bạn sẽ có bao nhiêu loại bố cục - bạn có thể sử dụng các phương pháp đó.

getViewTypeCount() - điều này phương pháp trả về thông tin có bao nhiêu loại hàng làm bạn có trong danh sách của bạn

getItemViewType(int position) - trả về thông tin loại bố trí, bạn nên sử dụng dựa trên vị trí

Sau đó, bạn thổi phồng bố trí duy nhất nếu nó là null và xác định loại sử dụng getItemViewType.

Nhìn vào this tutorial để biết thêm thông tin.

Để đạt được một số tối ưu trong cấu trúc mà bạn đã mô tả trong comment tôi sẽ đề nghị:

  • quan lưu trữ trong đối tượng được gọi là ViewHolder. Nó sẽ tăng tốc độ bởi vì bạn sẽ không phải gọi findViewById() mỗi lần trong phương thức getView. Xem List14 in API demos.
  • Tạo một bố cục chung chung sẽ phù hợp với tất cả các kết hợp thuộc tính và ẩn một số thành phần nếu vị trí hiện tại không có.

Tôi hy vọng điều đó sẽ giúp ích cho bạn. Nếu bạn có thể cung cấp một số bài XML với cấu trúc dữ liệu và thông tin của bạn chính xác như thế nào bạn muốn ánh xạ nó thành hàng, tôi sẽ có thể cung cấp cho bạn lời khuyên chính xác hơn. Theo pixel.

+0

Cảm ơn blog rất đẹp, nhưng tôi đã thêm hộp kiểm. Tôi đã có một vấn đề trong đó sẽ kiểm tra mục đầu tiên và di chuyển danh sách. Các mục ẩn danh lạ khi được kiểm tra. Bạn có thể cung cấp giải pháp cho điều đó không. Cảm ơn –

+2

xin lỗi vì đã đào lên điều này một lần nữa, nhưng bạn thực sự khuyên bạn nên có một tệp bố cục lớn duy nhất và kiểm soát khả năng hiển thị của các phần của nó, thay vì có các tệp bố cục riêng biệt, tăng lên tương ứng bằng cách sử dụng getItemViewType? – Makibo

+2

Bạn cũng có thể làm điều đó. Mặc dù tôi vẫn thích cách tiếp xúc ở đây. Nó làm cho rõ ràng hơn những gì bạn muốn đạt được. – Cristian

12

Trong bộ điều hợp mảng tùy chỉnh của bạn, bạn ghi đè phương thức getView(), như bạn có thể đã quen thuộc. Sau đó, tất cả những gì bạn phải làm là sử dụng một câu lệnh switch hoặc câu lệnh if để trả về một View tùy chỉnh nào đó tùy thuộc vào đối số vị trí được truyền cho phương thức getView. Android là thông minh ở chỗ nó sẽ chỉ cung cấp cho bạn một convertView của loại thích hợp cho vị trí/hàng của bạn; bạn không cần phải kiểm tra xem nó có đúng loại hay không. Bạn có thể giúp Android với điều này bằng cách ghi đè phương thức getItemViewType() và getViewTypeCount() một cách thích hợp.

60

Tôi biết cách tạo hàng tùy chỉnh + bộ điều hợp mảng tùy chỉnh để hỗ trợ hàng tùy chỉnh cho toàn bộ chế độ xem danh sách. Nhưng làm thế nào một listview có thể hỗ trợ nhiều kiểu hàng khác nhau?

Bạn đã biết những điều cơ bản. Bạn chỉ cần nhận bộ điều hợp tùy chỉnh của mình để trả lại bố cục/chế độ xem khác dựa trên thông tin hàng/con trỏ được cung cấp.

Một ListView có thể hỗ trợ nhiều kiểu hàng bởi vì nó xuất phát từ AdapterView:

Một AdapterView là một cái nhìn mà trẻ em được xác định bởi một Adapter.

Nếu bạn nhìn vào Adapter, bạn sẽ thấy phương pháp mà chiếm sử dụng xem hàng cụ thể:

abstract int getViewTypeCount() 
// Returns the number of types of Views that will be created ... 

abstract int getItemViewType(int position) 
// Get the type of View that will be created ... 

abstract View getView(int position, View convertView, ViewGroup parent) 
// Get a View that displays the data ... 

Hai phương pháp sau cung cấp vị trí để bạn có thể sử dụng điều đó để xác định loại chế độ xem bạn nên sử dụng cho hàng đó.


Tất nhiên, bạn thường không sử dụng AdapterView và Adaptor trực tiếp mà sử dụng hoặc lấy được từ một trong các lớp con của chúng. Các lớp con của Bộ điều hợp có thể thêm chức năng bổ sung thay đổi cách nhận bố cục tùy chỉnh cho các hàng khác nhau. Vì chế độ xem được sử dụng cho một hàng nhất định được điều khiển bởi bộ điều hợp, mẹo là để bộ điều hợp trả về chế độ xem mong muốn cho một hàng nhất định. Cách thực hiện việc này khác nhau tùy thuộc vào bộ điều hợp cụ thể.

Ví dụ, để sử dụng ArrayAdapter,

  • override getView() để thổi phồng, cư, và trở về giao diện bạn muốn cho vị trí nhất định. Phương pháp getView() bao gồm cơ hội sử dụng lại lượt xem thông qua tham số convertView.

Nhưng để sử dụng các dẫn xuất của CursorAdapter,

  • override newView() để thổi phồng, cư, và trở về giao diện bạn muốn cho tình trạng con trỏ hiện hành (tức là "hàng" hiện nay) [bạn cũng cần ghi đè bindView để tiện ích con có thể sử dụng lại chế độ xem]

Tuy nhiên, để sử dụng SimpleCursorAdapter,

  • định nghĩa một SimpleCursorAdapter.ViewBinder với một phương pháp setViewValue() để thổi phồng, cư, và trở về giao diện bạn muốn cho một hàng nhất định (tình trạng con trỏ hiện hành) và dữ liệu "cột". Phương thức này có thể định nghĩa các khung nhìn "đặc biệt" và trì hoãn hành vi chuẩn của SimpleCursorAdapter cho các ràng buộc "bình thường".

Tra cứu các ví dụ/hướng dẫn cụ thể cho loại bộ điều hợp mà bạn sử dụng.

+0

Bất kỳ suy nghĩ nào về loại bộ điều hợp nào là tốt nhất để thực hiện linh hoạt bộ điều hợp? Tôi đang thêm một câu hỏi khác trên bảng cho việc này. – Androider

+1

@Androider - "tốt nhất cho linh hoạt" là rất cởi mở - không có kết thúc tất cả, tất cả các lớp sẽ đáp ứng mọi nhu cầu; nó là một hệ thống phân cấp phong phú - nó đi xuống đến việc liệu có chức năng nào trong một lớp con hữu ích cho mục đích của bạn hay không. Nếu có, hãy bắt đầu với phân lớp đó; nếu không, hãy chuyển lên 'BaseAdapter'. Xuất phát từ BaseAdapter sẽ là "linh hoạt nhất", nhưng sẽ là điều tồi tệ nhất khi sử dụng lại và đáo hạn mã vì nó không tận dụng được kiến ​​thức và sự trưởng thành đã được đưa vào các adapter khác. 'BaseAdapter' có các ngữ cảnh không chuẩn, nơi các adapter khác không phù hợp. –

+3

+1 cho sự khác biệt tốt giữa 'CursorAdapter' và' SimpleCursorAdapter'. –

3

Nếu chúng tôi cần hiển thị loại chế độ xem khác nhau trong chế độ xem danh sách thì tốt nhất là sử dụng getViewTypeCount() và getItemViewType() trong bộ điều hợp thay vì chuyển sang chế độ xem VIEW.GONE và VIEW.VISIBLE có thể là công việc rất tốn kém bên trong getView() sẽ ảnh hưởng đến danh sách cuộn.

Vui lòng kiểm tra điều này để sử dụng getViewTypeCount() và getItemViewType() trong Bộ điều hợp.

Link: the-use-of-getviewtypecount

1

ListView được dự định đối với trường hợp sử dụng đơn giản như quan điểm tĩnh tương tự cho tất cả các mục hàng.
Vì bạn phải tạo ViewHolders và sử dụng đáng kể getItemViewType() và tự động hiển thị bố cục mục hàng khác nhau của xml, bạn nên thử làm điều đó bằng cách sử dụng RecyclerView, có sẵn trong API Android 22. Nó cung cấp hỗ trợ và cấu trúc tốt hơn cho nhiều chế độ xem loại.

Kiểm tra điều này tutorial về cách sử dụng RecyclerView để thực hiện những gì bạn đang tìm kiếm.

35

Hãy xem mã bên dưới.

Trước tiên, chúng tôi tạo bố cục tùy chỉnh. Trong trường hợp này, bốn loại.

even.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:background="#ff500000" 
    android:layout_height="match_parent"> 

    <TextView 
     android:id="@+id/text" 
     android:textColor="@android:color/white" 
     android:layout_width="match_parent" 
     android:layout_gravity="center" 
     android:textSize="24sp" 
     android:layout_height="wrap_content" /> 

</LinearLayout> 

odd.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:background="#ff001f50" 
    android:gravity="right" 
    android:layout_height="match_parent"> 

    <TextView 
     android:id="@+id/text" 
     android:textColor="@android:color/white" 
     android:layout_width="wrap_content" 
     android:layout_gravity="center" 
     android:textSize="28sp" 
     android:layout_height="wrap_content" /> 

</LinearLayout> 

white.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:background="#ffffffff" 
    android:gravity="right" 
    android:layout_height="match_parent"> 

    <TextView 
     android:id="@+id/text" 
     android:textColor="@android:color/black" 
     android:layout_width="wrap_content" 
     android:layout_gravity="center" 
     android:textSize="28sp" 
     android:layout_height="wrap_content" /> 

</LinearLayout> 

black.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:background="#ff000000" 
    android:layout_height="match_parent"> 

    <TextView 
     android:id="@+id/text" 
     android:textColor="@android:color/white" 
     android:layout_width="wrap_content" 
     android:layout_gravity="center" 
     android:textSize="33sp" 
     android:layout_height="wrap_content" /> 

</LinearLayout> 

Sau đó, chúng ta tạo mục listview. Trong trường hợp của chúng ta, với một chuỗi và một kiểu.

public class ListViewItem { 
     private String text; 
     private int type; 

     public ListViewItem(String text, int type) { 
      this.text = text; 
      this.type = type; 
     } 

     public String getText() { 
      return text; 
     } 

     public void setText(String text) { 
      this.text = text; 
     } 

     public int getType() { 
      return type; 
     } 

     public void setType(int type) { 
      this.type = type; 
     } 

    } 

Sau đó, chúng tôi tạo chế độ xem. Bạn nên sử dụng hệ điều hành Android vì hệ điều hành Android giữ nguyên tham chiếu bố cục để sử dụng lại mục của bạn khi nó biến mất và xuất hiện trở lại trên màn hình. Nếu bạn không sử dụng phương pháp này, mỗi lần mục của bạn xuất hiện trên màn hình, hệ điều hành Android sẽ tạo ra một ứng dụng mới và khiến ứng dụng của bạn bị rò rỉ bộ nhớ.

public class ViewHolder { 
     TextView text; 

     public ViewHolder(TextView text) { 
      this.text = text; 
     } 

     public TextView getText() { 
      return text; 
     } 

     public void setText(TextView text) { 
      this.text = text; 
     } 

    } 

Cuối cùng, chúng tôi tạo bộ điều hợp tùy chỉnh ghi đè getViewTypeCount() và getItemViewType (vị trí int).

public class CustomAdapter extends ArrayAdapter { 

     public static final int TYPE_ODD = 0; 
     public static final int TYPE_EVEN = 1; 
     public static final int TYPE_WHITE = 2; 
     public static final int TYPE_BLACK = 3; 

     private ListViewItem[] objects; 

     @Override 
     public int getViewTypeCount() { 
      return 4; 
     } 

     @Override 
     public int getItemViewType(int position) { 
      return objects[position].getType(); 
     } 

     public CustomAdapter(Context context, int resource, ListViewItem[] objects) { 
      super(context, resource, objects); 
      this.objects = objects; 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 

      ViewHolder viewHolder = null; 
      ListViewItem listViewItem = objects[position]; 
      int listViewItemType = getItemViewType(position); 


      if (convertView == null) { 

       if (listViewItemType == TYPE_EVEN) { 
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_even, null); 
       } else if (listViewItemType == TYPE_ODD) { 
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_odd, null); 
       } else if (listViewItemType == TYPE_WHITE) { 
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_white, null); 
       } else { 
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_black, null); 
       } 

       TextView textView = (TextView) convertView.findViewById(R.id.text); 
       viewHolder = new ViewHolder(textView); 

       convertView.setTag(viewHolder); 

      } else { 
       viewHolder = (ViewHolder) convertView.getTag(); 
      } 

      viewHolder.getText().setText(listViewItem.getText()); 

      return convertView; 
     } 

    } 

Và hoạt động của chúng tôi là một cái gì đó như thế này:

private ListView listView; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_main); // here, you can create a single layout with a listview 

     listView = (ListView) findViewById(R.id.listview); 

     final ListViewItem[] items = new ListViewItem[40]; 

     for (int i = 0; i < items.length; i++) { 
      if (i == 4) { 
       items[i] = new ListViewItem("White " + i, CustomAdapter.TYPE_WHITE); 
      } else if (i == 9) { 
       items[i] = new ListViewItem("Black " + i, CustomAdapter.TYPE_BLACK); 
      } else if (i % 2 == 0) { 
       items[i] = new ListViewItem("EVEN " + i, CustomAdapter.TYPE_EVEN); 
      } else { 
       items[i] = new ListViewItem("ODD " + i, CustomAdapter.TYPE_ODD); 
      } 
     } 

     CustomAdapter customAdapter = new CustomAdapter(this, R.id.text, items); 
     listView.setAdapter(customAdapter); 
     listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
      @Override 
      public void onItemClick(AdapterView adapterView, View view, int i, long l) { 
       Toast.makeText(getBaseContext(), items[i].getText(), Toast.LENGTH_SHORT).show(); 
      } 
     }); 

    } 
} 

nay tạo ra một listview bên mainactivity.xml như cập nhật

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context="com.example.shivnandan.gygy.MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:popupTheme="@style/AppTheme.PopupOverlay" /> 

    </android.support.design.widget.AppBarLayout> 

    <include layout="@layout/content_main" /> 

    <ListView 
     android:layout_width="match_parent" 

     android:layout_height="match_parent" 

     android:id="@+id/listView" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentEnd="true" 


     android:layout_marginTop="100dp" /> 

</android.support.design.widget.CoordinatorLayout> 
+0

Cảm ơn bạn, nó hoạt động. – oguzhan

+0

từ đó đến từ đâu – nyxee

Các vấn đề liên quan