Nền mục ListView qua bộ chọn tùy chỉnh


98

Có thể áp dụng nền tùy chỉnh cho từng mục Listview thông qua bộ chọn danh sách không?

Bộ chọn mặc định chỉ định @android:color/transparentcho state_focused="false"trường hợp, nhưng việc thay đổi điều này thành một số tùy chỉnh có thể kéo không ảnh hưởng đến các mục không được chọn. Romain Guy dường như gợi ý trong câu trả lời rằng điều này là có thể.

Tôi hiện đang đạt được ảnh hưởng tương tự bằng cách sử dụng nền tùy chỉnh trên mỗi chế độ xem và ẩn nó khi mục được chọn / tiêu điểm / bất cứ thứ gì để bộ chọn được hiển thị, nhưng sẽ thanh lịch hơn nếu tất cả điều này được xác định ở một nơi.

Để tham khảo, đây là bộ chọn tôi đang sử dụng để thử và làm cho nó hoạt động:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="false"
        android:drawable="@drawable/list_item_gradient" />

    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
    <item android:state_focused="true" android:state_enabled="false"
        android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_disabled" />
    <item android:state_focused="true" android:state_enabled="false"
        android:drawable="@drawable/list_selector_background_disabled" />

    <item android:state_focused="true" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />
    <item android:state_focused="false" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />

    <item android:state_focused="true"
        android:drawable="@drawable/list_selector_background_focus" />

</selector>

Và đây là cách tôi thiết lập bộ chọn:

<ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:listSelector="@drawable/list_selector_background" />    

Cảm ơn trước sự giúp đỡ nào!

Câu trả lời:


128

Bản thân tôi đã rất thất vọng vì điều này và cuối cùng đã giải quyết được nó. Như Romain Guy đã gợi ý, có một trạng thái khác "android:state_selected", mà bạn phải sử dụng. Sử dụng trạng thái có thể vẽ cho nền của mục danh sách của bạn và sử dụng trạng thái có thể vẽ khác cholistSelector danh sách của bạn:

list_row_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:background="@drawable/listitem_background"
    >
...
</LinearLayout>

listitem_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@color/android:transparent" />
    <item android:drawable="@drawable/listitem_normal" />
</selector>

layout.xml bao gồm ListView:

...
<ListView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:listSelector="@drawable/listitem_selector"
   />
...

listitem_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/listitem_pressed" />
    <item android:state_focused="true" android:drawable="@drawable/listitem_selected" />
</selector>

1
Cảm ơn vì câu trả lời chuyên sâu. Như tôi đã đề cập trong câu hỏi của mình, đây chính xác là những gì tôi đang làm vào lúc này và nó hoạt động khá tốt.
shilgapira

Rất tiếc, tôi vẫn gặp sự cố khi tùy chỉnh chế độ xem danh sách của mình. Tôi đã đăng các vấn đề cụ thể của mình ở đây: stackoverflow.com/questions/5426385/… ; Tôi sẽ đánh giá cao bất kỳ đầu vào nào bạn có thể có.
LostNomad311,

Nó không hoạt động khi bạn sử dụng các ngăn kéo 9 bản vá với phần đệm làm nền. Tôi đã tìm thấy giải pháp cuối cùng, tôi nghĩ, hãy xem câu trả lời của tôi
Michał K

Điều này hoạt động đối với hậu ICS, nhưng đối với Gingerbread, toàn bộ danh sách được tô màu bằng cách nhấn hoặc có thể vẽ được chọn.
gunar

Có giải pháp nào cho ICS trước không?
Lonli-Lokli

78

Giải pháp của dglmtn không hoạt động khi bạn có bản vẽ 9 bản vá với phần đệm làm nền. Những điều kỳ lạ xảy ra, tôi thậm chí không muốn nói về nó, nếu bạn có một vấn đề như vậy, bạn biết chúng.

Bây giờ, nếu bạn muốn có một listview với các trạng thái khác nhau và các bảng vẽ 9 bản vá (nó sẽ hoạt động với bất kỳ bảng vẽ và màu nào, tôi nghĩ) bạn phải làm 2 điều:

  1. Đặt bộ chọn cho các mục trong danh sách.
  2. Loại bỏ bộ chọn mặc định cho danh sách.

Điều bạn nên làm trước tiên là đặt row_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_enabled="true" 
     android:state_pressed="true" android:drawable="@drawable/list_item_bg_pressed" />
    <item android:state_enabled="true"
     android:state_focused="true" android:drawable="@drawable/list_item_bg_focused" />
    <item android:state_enabled="true"
     android:state_selected="true" android:drawable="@drawable/list_item_bg_focused" />
    <item
     android:drawable="@drawable/list_item_bg_normal" />
</selector>

Đừng quên android:state_selected. Nó hoạt động giống như android:state_focusedcho danh sách, nhưng nó được áp dụng cho mục danh sách.

Bây giờ áp dụng bộ chọn cho các mục (row.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/row_selector"
>
...
</RelativeLayout>

Tạo một bộ chọn trong suốt cho danh sách:

<ListView
    android:id="@+id/android:list"
    ...
    android:listSelector="@android:color/transparent"
    />

Điều này sẽ làm điều.


1
+1, Tôi không thấy câu trả lời của bạn trước đây, tôi đã tìm thấy kết quả tương tự khi tự mình làm điều đó. Nhưng cảm ơn vì đã đề cập đến 9-patch drawables, tôi chắc chắn rằng nó có thể hữu ích trong việc triển khai trong tương lai của tôi. Đây phải là câu trả lời tốt nhất vì phương pháp này sạch hơn và có thể bảo trì được.
IsaacCisneros

28
Tôi xin lỗi, nhưng đây là loại điều khiến đôi khi phải suy nghĩ tại sao những apis giao diện người dùng chết tiệt này lại phải tồi tệ đến vậy. Android vẫn còn rất nhiều điều phải trải qua. Những thứ cơ bản như vậy không nên là một PITA như vậy.
Gubatron

2
+1 Cảm ơn bạn, cảm ơn bạn, cảm ơn bạn. Nhảy qua tất cả những vòng này để đạt được điều gì đó rất cơ bản. Tất cả những trạng thái này rất khó hiểu.
Moritz

3
Thay vì android: listSelector = "@ drawable / list_selector" chỉ cần viết android: listSelector = "@ android: color / transparent". Không cần thêm list_selector.xml.
Sofi Software LLC,

1
Chính xác, bộ chọn danh sách không hủy chỉ có thể là @android: color / transparent thay vì bộ chọn xml của riêng bạn. Chỉ cần thử nó. Điều không hoạt động là @ null, điều này làm tôi ngạc nhiên vì điều đó phải nêu rõ: "không có bộ chọn danh sách" và vì bộ chọn danh sách được vẽ phía sau mục, không nên vẽ gì. Nhưng điều đó không làm việc, chọn mặc định là trở lại sau đó ...
Zordid

17

Không bao giờ sử dụng "màu nền" cho các hàng chế độ xem danh sách của bạn ...

điều này sẽ chặn mọi hành động của bộ chọn (là vấn đề của tôi!)

chúc may mắn!


3
Đây không phải là sự thật. Chỉ sử dụng bộ chọn làm nền, không phải màu tĩnh hoặc có thể vẽ được
Michał K

điều này được dự định có nghĩa là "màu nền". hoàn toàn nhận lời.
cV2

Tôi đến đây vì tôi cần một bộ chọn bây giờ tôi đã sử dụng setBackgroundColorvới "màu". Thở dài ... Sử dụng setBackgroundhoặc setBackgroundDrawabletheo phiên bản API của bạn với một bộ chọn.
EpicPandaForce

5

Bài viết "Tại sao danh sách của tôi có màu đen? Tối ưu hóa Android" trên Blog nhà phát triển Android đã giải thích cặn kẽ về lý do tại sao nền danh sách chuyển sang màu đen khi cuộn. Câu trả lời đơn giản: đặt cacheColorHint trên danh sách của bạn thành trong suốt (# 00000000).


1
Một sự đơn giản mẫu mực nhưng nó hoạt động rất tốt. Cảm ơn Romain Guy ... <ListView ... android: cacheColorHint = "# 00000000"> </ListView> Tất cả!
Eric JOYÉ

Đừng cảm ơn Romain Guy. Anh ấy là một phần của vấn đề. Không nên có quá nhiều "thủ thuật ẩn" hoặc các cách hack khác trong một hệ điều hành như thế này. Mặc dù tôi yêu thích Android, nhưng đó là một đống dogcrap lớn khi so sánh với các SDK khác (ngay cả những SDK mới hơn / ít trưởng thành hơn!).
StackOverflow đã

5

Nó là đủ, nếu bạn đưa vào list_row_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/listitem_background">... </LinearLayout>

listitem_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/dark" android:state_pressed="true" />
    <item android:drawable="@color/dark" android:state_focused="true" />
    <item android:drawable="@android:color/white" />
</selector>

2
tuyệt vời ... đơn giản nhất ví dụ
Shihab Uddin

1
Và cũng làm cho bộ chọn listview minh bạch
Sayka

4

thay vì:

android:drawable="@color/transparent" 

viết

android:drawable="@android:color/transparent"

4

Bạn có thể viết một chủ đề:

<pre>

    android:name=".List10" android:theme="@style/Theme"

theme.xml

<style name="Theme" parent="android:Theme">
        <item name="android:listViewStyle">@style/MyListView</item>
</style>

styles.xml

 <style name="MyListView" parent="@android:style/Widget.ListView">
<item name="android:listSelector">@drawable/my_selector</item>

my_selector là công cụ chọn tùy chỉnh của bạn. Tôi xin lỗi, tôi không biết cách viết mã của mình


Cảm ơn sự trợ giúp, nhưng điều này không trực tiếp giúp đặt nền listitem mặc định thông qua bộ chọn.
shilgapira

2

Tôi không chắc làm thế nào để đạt được hiệu ứng mong muốn của bạn thông qua chính bộ chọn - xét cho cùng, theo định nghĩa, có một bộ chọn cho toàn bộ danh sách.

Tuy nhiên, bạn có thể kiểm soát các thay đổi lựa chọn và vẽ bất cứ thứ gì bạn muốn. Trong dự án mẫu này , tôi làm cho bộ chọn trong suốt và vẽ một thanh trên mục đã chọn.


Thật vậy, hoàn toàn hợp lý khi chỉ có nhiều nhất một bộ chọn. Tôi đoán tôi (hoặc đã) hơi bối rối bởi sự tồn tại của <item android:state_focused="false" android:drawable="@android:color/transparent" />mệnh đề trong bộ chọn mặc định.
shilgapira

Mark, đang chơi xung quanh (gặp vấn đề tương tự như Gil). Tôi đã thử giải pháp của bạn, nó chỉ là một phần chỉ dành cho đường bóng thôi, không có gì. bạn phải theo dõi các vị trí đã chọn và được nhấn bên trong ListView và vẽ những gì bạn cần trong chính Item (đặt nó ở dạng xem tùy chỉnh) và trong DispatchDraw của ListView.
codeScriber

@codeScriber: "nothingSeelected được gọi khi bạn chạm vào các mục chỉ bằng cách chạm và onItemClicked được kích hoạt" - đây là hành vi hoàn toàn bình thường, vì thao tác chạm không liên quan gì đến lựa chọn.
CommonsWare

2

Tôi luôn sử dụng cùng một phương pháp và nó hoạt động mọi lúc, mọi nơi: Tôi chỉ đơn giản sử dụng một bộ chọn như thế này

<item android:state_activated="true"  android:color="@color/your_selected_color" />
<item android:state_pressed="true" android:color="@color/your_pressed_color" />
<item android:color="@color/your_normal_color"></item>

và đặt trên ListView (ĐIỀU NÀY RẤT QUAN TRỌNG ĐỂ LÀM cho nó hoạt động) thuộc tính

android:choiceMode="singleChoice"

đối với textColor chỉ cần đặt trong thư mục màu (QUAN TRỌNG, không phải thư mục có thể vẽ được!) một bộ chọn như thế này

<item android:state_activated="true"  android:color="@color/your_selected_textColor" />
<item android:state_pressed="true" android:color="@color/your_pressed_textColor" />
<item android:color="@color/your_normal_textColor"></item>

đây là một mẫu hàng mẫu

<ImageView
    android:id="@+skinMenu/lblIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:src="@drawable/menu_catalog" />

<TextView
    android:id="@+skinMenu/lblTitle"
    style="@style/superlabelStyle"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_marginLeft="20dp"
    android:gravity="center_vertical"
    android:text="test menu testo"
    android:textColor="@color/menu_textcolor_selector"
    android:textSize="20dp"
    android:textStyle="bold" />

mọi thứ đều hoạt động mà không có cách giải quyết tẻ nhạt. hy vọng điều này giúp đỡ


-3

Đội FrostWire ở đây.

Tất cả api crap của bộ chọn không hoạt động như mong đợi. Sau khi thử tất cả các giải pháp được trình bày trong chuỗi này đều không tốt, chúng tôi vừa giải quyết được vấn đề tại thời điểm thổi phồng Mục ListView.

  1. Đảm bảo rằng mục của bạn giữ trạng thái của nó, chúng tôi đã làm nó như một biến thành viên của MenuItem (đã chọn boolean)

  2. Khi bạn phóng to, hãy hỏi xem mục bên dưới có được chọn hay không, nếu có, chỉ cần đặt tài nguyên có thể vẽ mà bạn muốn làm nền (có thể là 9patch hoặc bất cứ thứ gì). Đảm bảo rằng bộ điều hợp của bạn biết điều này và nó sẽ gọi thông báoDataChanged () khi một cái gì đó đã được chọn.

        @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        if (rowView == null) {
            LayoutInflater inflater = act.getLayoutInflater();
            rowView = inflater.inflate(R.layout.slidemenu_listitem, null);
            MenuItemHolder viewHolder = new MenuItemHolder();
            viewHolder.label = (TextView) rowView.findViewById(R.id.slidemenu_item_label);
            viewHolder.icon = (ImageView) rowView.findViewById(R.id.slidemenu_item_icon);
            rowView.setTag(viewHolder);
        }
    
        MenuItemHolder holder = (MenuItemHolder) rowView.getTag();
        String s = items[position].label;
        holder.label.setText(s);
        holder.icon.setImageDrawable(items[position].icon);
    
        //Here comes the magic
        rowView.setSelected(items[position].selected);
    
        rowView.setBackgroundResource((rowView.isSelected()) ? R.drawable.slidemenu_item_background_selected : R.drawable.slidemenu_item_background);
    
        return rowView;
    }

Sẽ thực sự tốt nếu các bộ chọn thực sự hoạt động, về lý thuyết thì đó là một giải pháp tốt và thanh lịch, nhưng có vẻ như nó đã bị hỏng. HÔN.


Tôi muốn thử giải pháp này, bạn có thể vui lòng giải thích chi tiết hơn hoặc giải pháp hoàn chỉnh không? Cảm ơn
Andrew Lam
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.