จะเปิด onListItemClick ใน Listactivity พร้อมปุ่มในรายการได้อย่างไร?


89

ฉันมี ListActivity ง่ายๆที่ใช้ ListAdapter แบบกำหนดเองเพื่อสร้างมุมมองในรายการ โดยปกติ ListAdapter จะเติมมุมมองด้วย TextViews แต่ตอนนี้ฉันต้องการใส่ปุ่มที่นั่นด้วย

เป็นความเข้าใจและประสบการณ์ของฉันอย่างไรก็ตามการวางมุมมองที่โฟกัสได้ในรายการจะป้องกันการเริ่มทำงานของ onListItemClick () ใน ListActivity เมื่อรายการถูกคลิก ปุ่มยังคงทำงานตามปกติภายในรายการ แต่เมื่อมีการกดบางอย่างนอกเหนือจากปุ่มฉันต้องการให้ onListItemClick ถูกทริกเกอร์

ฉันจะทำงานนี้ได้อย่างไร?


5
วิธีการแก้ปัญหาของคุณด้วย Focusability ที่สืบทอดมานั้นช่วยได้มากคุณควรเพิ่มเป็นคำตอบและยอมรับมัน!
Maksym Gontar

@ แม็กซ์เหตุผลที่ฉันไม่เป็นเพราะมันเป็นการปฏิบัติที่ไม่ดีจริงๆเป็นวิธีแก้ปัญหา หากฉันเคยพบวิธีแก้ปัญหาที่ดีต่อสุขภาพอย่างถาวรฉันจะทำคำตอบนั้น (ถ้าฉันจำได้ว่าฉันเคยเขียนคำถามนี้เมื่อปีที่แล้ว :))
CodeFusionMobile

ฉันต้องการดูวิธีแก้ปัญหาที่คุณมี ฉันพยายามตั้งค่าโฟกัสแบบสืบทอดและไม่สามารถใช้งานกับปุ่มต่างๆได้ นอกจากนี้ฉันยังพยายามใส่ GridView (พร้อม ImageViews) ในแถวรายการและมีปัญหาที่คล้ายกัน
MrPurpleStreak

คำตอบของ IMHO ที่ฉันให้เป็นวิธีแก้ปัญหาที่สวยงามกว่ามากจากนั้นคำตอบที่เสนอโดย Ramps และ Praveen Ps ไม่ได้พยายามที่จะรื้อฟื้นคำถามที่ถูกลืมที่นี่ แต่ฉันเห็นว่าคุณยังไม่ยอมรับคำตอบใด ๆ D
Ewoks

@CodeFusionMobile คุณช่วยยอมรับคำตอบของ Ewoks ได้ไหม? คำตอบที่ได้รับการโหวตสูงสุดมีข้อบกพร่องเนื่องจากปิดใช้งานภาพเคลื่อนไหว onclick สำหรับองค์ประกอบ ListView (โดยที่เปลี่ยนเป็นสีน้ำเงิน) มันจะช่วยประหยัดเวลานักพัฒนาคนอื่น ๆ ในการลองใช้คำตอบยอดนิยมค้นหาว่ามีข้อบกพร่องจากนั้นไปที่ Ewoks
1 ''

คำตอบ:


99

ตามที่ฉันเขียนไว้ในวิธีแก้ปัญหาความคิดเห็นก่อนหน้านี้คือ setFocusable (เท็จ) บน ImageButton

มีวิธีแก้ปัญหาที่หรูหรายิ่งขึ้นให้ลองเพิ่มandroid:descendantFocusability="blocksDescendants" เค้าโครงรูทขององค์ประกอบรายการ นั่นจะทำให้การคลิก onListItem เป็นไปได้และแยกกันคุณสามารถจัดการกับการคลิกปุ่มหรือ ImageButton

หวังว่ามันจะช่วย;)

ไชโย


3
android:descendantFocusability="blocksDescendants"สมบูรณ์แบบ
Matthew Mitchell

1
คุณเพื่อนของฉันเป็นฮีโร่ส่วนตัวของฉัน คุณควรเป็นคนที่ได้รับการโหวตสูงสุด! ดีกว่ามากสำหรับเกือบทุกกรณี!
OschtärEi

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ดูเหมือนว่ามุมมองทั้งหมดในรายการจะต้องไม่สามารถโฟกัสได้และมุมมองนี้ทำได้โดยไม่ต้องตั้งค่าทีละรายการ
วิ่ง

1
สิ่งนี้ดูเหมือนจะไม่ได้ผลสำหรับฉัน ตามเค้าโครงรูทคุณหมายถึงเค้าโครงแถวหรือที่กำหนดมุมมองรายการหรือไม่? อย่างไรก็ตามฉันลองใช้ชุดค่าผสมที่เป็นไปได้ทั้งหมด .. ไม่ได้ผล :(
GreenBee

"เค้าโครงรูทขององค์ประกอบรายการ" ตามที่ฉันเขียน .. สมมติว่าคุณมีรายการและประกอบด้วยเลย์เอาต์ (เรียกว่าเค้าโครงรูทขององค์ประกอบรายการ) ที่มีหลายปุ่ม, ImageButton, TextVeiw ..
Ewoks

59

ฉันหวังว่าฉันจะสามารถช่วยได้ที่นี่ ฉันคิดว่าคุณมีเค้าโครงที่กำหนดเองสำหรับรายการ listView และเค้าโครงนี้ประกอบด้วยปุ่มและมุมมองอื่น ๆ เช่น TextView, ImageView หรืออะไรก็ตาม ตอนนี้คุณต้องการให้เหตุการณ์ต่างๆเริ่มขึ้นเมื่อคลิกปุ่มและเหตุการณ์ที่แตกต่างกันเกิดขึ้นกับทุกสิ่งที่คลิก

คุณสามารถทำได้โดยไม่ต้องใช้ onListItemClick () ของ ListActivity ของคุณ
นี่คือสิ่งที่คุณต้องทำ:

คุณกำลังใช้เลย์เอาต์แบบกำหนดเองดังนั้นคุณอาจกำลังลบล้างเมธอด getView () จากอะแดปเตอร์ที่คุณกำหนดเอง เคล็ดลับคือการตั้งค่าผู้ฟังที่แตกต่างกันสำหรับปุ่มของคุณและแตกต่างกันสำหรับมุมมองทั้งหมด (แถวของคุณ) ดูตัวอย่าง:

private class MyAdapter extends ArrayAdapter<String> implements OnClickListener {

    public MyAdapter(Context context, int resource, int textViewResourceId,
            List<String> objects) {
        super(context, resource, textViewResourceId, objects);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String text = getItem(position);
        if (null == convertView) {
            convertView = mInflater.inflate(R.layout.custom_row, null);
        }
        //take the Button and set listener. It will be invoked when you click the button.
        Button btn = (Button) convertView.findViewById(R.id.button);
        btn.setOnClickListener(this);
        //set the text... not important     
        TextView tv = (TextView) convertView.findViewById(R.id.text);
        tv.setText(text);
        //!!! and this is the most important part: you are settin listener for the whole row
        convertView.setOnClickListener(new OnItemClickListener(position));
        return convertView;
    }

    @Override
    public void onClick(View v) {
        Log.v(TAG, "Row button clicked");
    }
}

คลาส OnItemClickListener ของคุณสามารถประกาศได้ดังนี้:

private class OnItemClickListener implements OnClickListener{       
    private int mPosition;
    OnItemClickListener(int position){
        mPosition = position;
    }
    @Override
    public void onClick(View arg0) {
        Log.v(TAG, "onItemClick at position" + mPosition);          
    }       
}

แน่นอนว่าคุณอาจจะต้องเพิ่มพารามิเตอร์ให้กับตัวสร้าง OnItemClickListener
และสิ่งหนึ่งที่สำคัญ - การใช้งาน getView ที่แสดงด้านบนนั้นค่อนข้างน่าเกลียดโดยปกติคุณควรใช้รูปแบบ ViewHolder เพื่อหลีกเลี่ยงการเรียก findViewById .. แต่คุณอาจรู้อยู่แล้ว
ไฟล์ custom_row.xml ของฉันคือ RelativeLayout พร้อมด้วย Button of id "button", TextView ของ id "text" และ ImageView ของ id "image" - เพื่อให้ทุกอย่างชัดเจน
ความนับถือ!


9
ทางออกของฉันไปอีกทางหนึ่ง ฉันแก้ไขปัญหาโดยการตั้งค่าคุณสมบัติ Focusability ที่สืบทอดมาของเค้าโครงแถวรายการเพื่อบล็อกลูกหลานและทันใดนั้นมันก็ใช้งานได้ ตอนนี้ฉันใช้ simpleCursorAdapter ที่มีช่องมองภาพแบบกำหนดเองติดอยู่เพื่อทำการตั้งค่าเหตุการณ์และสิ่งที่น่าสนใจอื่น ๆ ที่เกี่ยวข้องกับปุ่ม
CodeFusionMobile

3
ฉันใช้วิธีนี้ อย่างไรก็ตามคำเตือน: หากตัวจัดการ onClick ของคุณทำให้เนื้อหาของรายการเปลี่ยนแปลงซึ่งจะส่งผลให้ getView ถูกเรียกและหากวิดเจ็ตของคุณเป็นสถานะ (เช่น ToggleButton หรือ CheckBox) และ getView ตั้งค่าสถานะนั้นคุณอาจต้องการ setOnClickListener (null) ก่อนที่คุณจะเปลี่ยนสถานะใน onView เพื่อหลีกเลี่ยงการได้รับผลกระทบแบบวนซ้ำ
Pierre-Luc Paour

3
แล้ววิธีแก้ปัญหาของฉันล่ะ? มีความประทับใจที่สวยหรูกว่าและทาได้ง่ายขึ้นทุกเมื่อที่ต้องการ ..
Ewoks

ความคิดเห็นแรกควรได้รับการยอมรับเป็นคำตอบดังนั้นคนอย่างฉันจะไม่ต้องใช้เวลาหลายชั่วโมงในการค้นหา
keybee

ขอบคุณ! นี่เป็นประโยชน์ ฉันชอบมันเป็นทางเลือกที่มีการแปลเป็นภาษาท้องถิ่นมากกว่าสำหรับโฟกัส: แนวทาง blockDescendants ที่อธิบายไว้ในเธรดอื่น ๆ
Yoav Shapira

18

เมื่อ ListView แบบกำหนดเองมีองค์ประกอบที่โฟกัสได้ onListItemClick จะไม่ทำงาน (ฉันคิดว่ามันเป็นพฤติกรรมที่คาดหวัง) เพียงแค่ลบโฟกัสออกจากมุมมองที่กำหนดเองมันจะทำเคล็ดลับ:

ตัวอย่างเช่น:

public class ExtendedCheckBoxListView extends LinearLayout {

    private TextView mText;
    private CheckBox mCheckBox;

    public ExtendedCheckBoxListView(Context context, ExtendedCheckBox aCheckBoxifiedText) {
         super(context);
         …
         mText.setFocusable(false);
         mText.setFocusableInTouchMode(false);

         mCheckBox.setFocusable(false);
         mCheckBox.setFocusableInTouchMode(false);
        …       
    }
}

3
ฉันชอบโซลูชันของคุณ: หากมีวิดเจ็ตที่ "คลิกได้" เพียงรายการเดียวต่อแถวการปฏิเสธความสามารถในการโฟกัสเป็นวิธีแก้ปัญหาที่ดี หมายความว่าการแตะที่ใดก็ได้ในแถวจะตรงกัน แต่นั่นเป็นพฤติกรรมที่มีประโยชน์เมื่อวิดเจ็ตเป็นวิทยุหรือช่องทำเครื่องหมาย สามารถทำได้เช่นเดียวกันใน XML โดยใช้ android: focusable = "false" และ android: focusableInTouchMode = "false"
Pierre-Luc Paour

1
ดูเหมือนว่าวิธี xml จะใช้ไม่ได้หากคุณเปลี่ยนการมองเห็นดังนั้นจึงต้องดำเนินการผ่านรหัสหลังจากตั้งค่า "มุมมอง" ให้มองเห็นได้
max4ever

13

ฉันมีปัญหาเดียวกัน: OnListItemClick ไม่ทำงาน! [แก้ไข]
สิ่งนี้เกิดขึ้นในคลาสที่ขยาย ListActivity
โดยมีเลย์เอาต์สำหรับ ListActivity ที่เนื้อหา TextBox และ ListView ซ้อนอยู่ใน LinearLayout
และเลย์เอาต์อื่นสำหรับแถว (กล่องกาเครื่องหมายและกล่องข้อความที่ซ้อนกันใน LineraLayout)

นั่นคือรหัส:

res / layout / configpage.xml (หลักสำหรับ ListActivity)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" > 
    <TextView  
        android:id="@+id/selection"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="pippo" /> 
    <ListView  
        android:id="@android:id/list"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:drawSelectorOnTop="false"  
        android:background="#aaFFaa" > 
    </ListView> 
<LinearLayout> 

res/layout/row.xml (layout for single row)  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"> 
  <CheckBox  
      android:id="@+id/img"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 

  <TextView  
      android:id="@+id/testo"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 
</LinearLayout> 

src /.../.../ ConfigPage.java

public class ConfigPage extends ListActivity
{
    TextView selection;

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.configpage);  
        // loaded from res/value/strings  
        String[] azioni = getResources().getStringArray(R.array.ACTIONS);  
        setListAdapter(new ArrayAdapter&lt;String&gt;(this, R.layout.row, 
                R.id.testo,   azioni));  
        selection = (TextView) findViewById(R.id.selection);  
    }       

    public void onListItemClick(ListView parent, View view, int position, long id)
    {
        selection.setText(" " + position);
    }
}

สิ่งนี้เริ่มทำงานเมื่อฉันเพิ่มลงใน row.xml

  • android:focusable="false"
  • android:focusableInTouchMode="false"

ฉันใช้ Eclipse 3.5.2
Android SDK 10.0.1
นาทีเวอร์ชัน SDK: 3

ฉันหวังว่านี่จะเป็นประโยชน์
... และขอโทษสำหรับภาษาอังกฤษของฉัน :(


@fellons ไม่รู้ว่าทำไม แต่มันไม่ได้ผลสำหรับฉัน onListItemClick ของฉันไม่ถูกเรียก
likejudo

คุณได้เพิ่มรหัสคุณสมบัติ android: focusable = "false" และ android: focusableInTouchMode = "false" code หรือไม่
rfellons


1

ฉันมีปัญหาเดียวกันกับ ToggleButton หลังจากครึ่งวันของการเอาหัวโขกกำแพงในที่สุดฉันก็แก้ไขได้ ทำได้ง่ายเพียงแค่ทำให้มุมมองที่โฟกัสไม่สามารถโฟกัสได้โดยใช้ "android: focusable" นอกจากนี้คุณควรหลีกเลี่ยงการเล่นกับความสามารถในการโฟกัสและความสามารถในการคลิก (ฉันเพิ่งสร้างเป็นคำ) ของแถวรายการเพียงแค่ปล่อยให้เป็นค่าเริ่มต้น

แน่นอนว่าตอนนี้มุมมองที่โฟกัสได้ของคุณในแถวรายการไม่สามารถโฟกัสได้ผู้ใช้ที่ใช้แป้นพิมพ์อาจมีปัญหาได้ดีโดยโฟกัสที่พวกเขา ไม่น่าจะเป็นปัญหา แต่ในกรณีที่คุณต้องการเขียนแอพที่สมบูรณ์แบบ 100% คุณสามารถใช้เหตุการณ์ onItemSelected เพื่อทำให้องค์ประกอบของแถวที่เลือกโฟกัสได้และองค์ประกอบของแถวที่เลือกก่อนหน้านี้ไม่สามารถโฟกัสได้


ฉันใช้แนวทางนี้ เป็นวิธีที่ง่ายที่สุดหากคุณสามารถแก้ไขปัญหาที่ไม่สามารถโฟกัสไปที่แต่ละรายการได้ นอกจากนี้ยังเก็บสถานะ drawables สำหรับรายการตามที่ควรจะเป็นซึ่งวิธีแก้ปัญหาอื่น ๆ บางส่วนไม่ทำ
Jonathan S.

1
 ListView lv = getListView();
lv.setTextFilterEnabled(true);

lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
    int position, long id) {
  // When clicked, show a toast with the TextView text
  Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
      Toast.LENGTH_SHORT).show();
}
});

-1

ฉันใช้ getListAdapter () getItem (ตำแหน่ง) สร้างอินสแตนซ์วัตถุที่เก็บค่าของฉันไว้ในรายการ

MyPojo myPojo = getListAdapter().getItem(position);

จากนั้นใช้เมธอด getter จาก myPojo ซึ่งจะเรียกค่าที่เหมาะสมภายในรายการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.