Android: รายการมุมมองที่มีหลายปุ่มที่คลิกได้


182

ฉันเป็นListViewที่ที่ทุกองค์ประกอบในรายการประกอบด้วย TextView และปุ่มที่แตกต่างกันสองปุ่ม บางสิ่งเช่นนี้

ListView
--------------------
[Text]
[Button 1][Button 2]
--------------------
[Text]
[Button 1][Button 2]
--------------------
... (and so on) ...

ด้วยรหัสนี้ฉันสามารถสร้างOnItemClickListenerรายการทั้งหมด:

listView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> list, View view, int position, long id) {
        Log.i(TAG, "onListItemClick: " + position);

        }

    }
});

อย่างไรก็ตามฉันไม่ต้องการให้คลิกทั้งรายการ แต่จะมีเพียงสองปุ่มของแต่ละรายการเท่านั้น

ดังนั้นคำถามของฉันคือฉันจะใช้งาน onClickListener อย่างไรสำหรับปุ่มทั้งสองด้วยพารามิเตอร์ต่อไปนี้:

  • int button (ปุ่มใดขององค์ประกอบที่ถูกคลิก)
  • int position (ซึ่งเป็นองค์ประกอบในรายการที่ปุ่มคลิกเกิดขึ้น)

อัปเดต:ฉันพบวิธีแก้ปัญหาตามที่อธิบายไว้ในคำตอบด้านล่าง ตอนนี้ฉันสามารถคลิก / แตะปุ่มผ่านหน้าจอสัมผัส อย่างไรก็ตามฉันไม่สามารถเลือกด้วยแทร็กบอลด้วยตนเอง มันก็จะเลือกรายการทั้งหมดและจากที่นั่นไปโดยตรงไปยังรายการต่อไปโดยไม่สนใจปุ่มแม้ว่าฉันชุด.setFocusable(true)และสำหรับปุ่มในsetClickable(true)getView()

ฉันยังเพิ่มรหัสนี้ลงในอะแดปเตอร์รายการที่กำหนดเองของฉัน:

@Override
public boolean  areAllItemsEnabled() {
    return false;           
}

@Override
public boolean isEnabled(int position) {
        return false;
}

ซึ่งทำให้ไม่มีรายการที่เลือกได้อีก แต่มันไม่ได้ช่วยในการเลือกปุ่มที่ซ้อนกัน

ใครมีความคิด?


สิ่งเหล่านี้จำเป็นหรือไม่
Stuart Axon

หากคุณดูที่รหัส BaseAdapter คุณจะเห็นว่า areAllItemsEnabled () และ isEnabled () นั้นเป็นรหัสฮาร์ดโค้ดที่เป็นจริงทำให้พวกมันเป็นตัวยึดตำแหน่งที่เรียบง่ายโดยไม่มีเหตุผลใด ๆ
Artem Russakovskii

ถ้าฉันต้องการใช้ SimpleCursorAdapter ฉันต้องทำอะแดปเตอร์ที่กำหนดเองเพื่อขยาย simplecursoradapter หรือไม่?
oratis

คำตอบ:


150

วิธีแก้ปัญหานี้ง่ายกว่าที่คิดจริงๆ คุณสามารถเพิ่มgetView()เมธอดของอะแดปเตอร์ที่กำหนดเองในsetOnClickListener () สำหรับปุ่มต่างๆ

ข้อมูลใด ๆ ที่เกี่ยวข้องกับปุ่มจะต้องเพิ่มด้วยmyButton.setTag()ในgetView()และสามารถเข้าถึงได้ใน onClickListener ผ่านview.getTag()

ฉันโพสต์วิธีแก้ปัญหาแบบละเอียดในบล็อกของฉันเป็นแบบฝึกหัด


2
แก้ไขแล้ว. ขอขอบคุณที่รายงาน :-)
znq

คุณได้รับ curItem.url จาก exacly เพียงใดคุณจะเจาะจงมากขึ้นหรือไม่
oratis

1
ขอบคุณ znq นั่นมันมีประโยชน์มากสำหรับฉัน ... บันทึกเวลาเป็นชุด
Nandagopal T

ดูการพูดคุยนี้เวลา 11:39 มีตัวอย่างที่ยอดเยี่ยม: youtu.be/wDBM6wVEO70?t=11m39s จากนั้นทำตามที่ @ znq พูดว่า ... setTag () เมื่อ convertView == เป็นโมฆะและ getTag () ใน onClick () วิธีการของปุ่ม onClickListener () ขอบคุณ!
Shehaaz

12
มันจะเป็นการดีถ้ามีคำตอบในตัวมันเองและไม่ได้ชี้ไปที่หน้าอื่น ลิงค์ของบล็อกนั้นตายแล้ว!
gsb

63

นี่เป็นคำตอบของภาคผนวก @ znq ...

มีหลายกรณีที่คุณต้องการทราบตำแหน่งแถวของรายการที่ถูกคลิกและคุณต้องการรู้ว่ามุมมองใดในแถวที่ถูกแตะ สิ่งนี้จะมีความสำคัญมากกว่าใน UIS ของแท็บเล็ต

คุณสามารถทำได้ด้วยอะแดปเตอร์ที่กำหนดเองดังต่อไปนี้:

private static class CustomCursorAdapter extends CursorAdapter {

    protected ListView mListView;

    protected static class RowViewHolder {
        public TextView mTitle;
        public TextView mText;
    }

    public CustomCursorAdapter(Activity activity) {
        super();
        mListView = activity.getListView();
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        // do what you need to do
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = View.inflate(context, R.layout.row_layout, null);

        RowViewHolder holder = new RowViewHolder();
        holder.mTitle = (TextView) view.findViewById(R.id.Title);
        holder.mText = (TextView) view.findViewById(R.id.Text);

        holder.mTitle.setOnClickListener(mOnTitleClickListener);
        holder.mText.setOnClickListener(mOnTextClickListener);

        view.setTag(holder);

        return view;
    }

    private OnClickListener mOnTitleClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            final int position = mListView.getPositionForView((View) v.getParent());
            Log.v(TAG, "Title clicked, row %d", position);
        }
    };

    private OnClickListener mOnTextClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            final int position = mListView.getPositionForView((View) v.getParent());
            Log.v(TAG, "Text clicked, row %d", position);
        }
    };
}

6
หรือคุณสามารถใช้บางอย่างเช่น ListView mListView = (ListView) v.getParent (). getParent ();
max4ever

1
ฉันจะรับตำแหน่งได้อย่างไรถ้าฉันใช้อะแดปเตอร์ในชั้นเรียนแยกต่างหาก ฉันใช้ตำแหน่งภายใน OnClickListener บางอย่างเช่น like_c.get (ตำแหน่ง) ขอแนะนำให้วางตำแหน่งสุดท้ายในเมธอด getView ของอะแด็ปเตอร์ ถ้าฉันทำการเปลี่ยนแปลงตำแหน่งที่ฉันได้รับจะเหมือนกันสำหรับรายการทั้งหมดใน lisview คุณช่วยแนะนำวิธีแก้ปัญหานี้ให้ฉันได้ไหม
Manikandan

นั่นเป็นเพราะเมื่อคุณใช้พารามิเตอร์ตำแหน่งของวิธีการ getView มันจะช่วยให้คุณตำแหน่งของรายการของรายการที่สร้างขึ้นล่าสุด แต่ไม่ใช่คนที่คุณคลิก
Archie.bpgc

@Manikandan: หากคุณใช้เมธอด getView () ของอแด็ปเตอร์คุณก็มีตำแหน่งที่ส่งถึงคุณใน params วิธีแล้ว ในกรณีนี้คุณสามารถใช้บางอย่างเช่น setTag () เพื่อจัดเก็บข้อมูลตำแหน่ง
greg7gkb

1
ฉันใช้รหัสของคุณในแอพของฉัน แต่เหตุการณ์คลิกเรียกหลังจากเกิดความล่าช้าหรือเมื่อฉันพยายามเลื่อนมุมมองรายการ ความคิดใด ๆ ว่าทำไมสิ่งนี้ถึงเกิดขึ้น?
Abdullah Umer

22

สำหรับผู้อ่านในอนาคต:

ในการเลือกปุ่มด้วยตนเองด้วยแทร็กบอลใช้:

myListView.setItemsCanFocus(true);

และเพื่อปิดการใช้งานการมุ่งเน้นที่รายการทั้งหมด:

myListView.setFocusable(false);
myListView.setFocusableInTouchMode(false);
myListView.setClickable(false);

มันใช้งานได้ดีสำหรับฉันฉันสามารถคลิกที่ปุ่มที่มีหน้าจอสัมผัสและยังเน้นที่การคลิกด้วยปุ่มกด


2
เพียงคนเดียวที่ช่วยฉัน! ขอบคุณมาก!
Onur

ExpandableListView แล้วฉันมีหลายมุมมองในรายการฉันแค่ต้องการมุมมองในลูกที่สามารถคลิกได้ขอบคุณ
twlkyao

12

ฉันไม่ได้มีประสบการณ์มากกว่าผู้ใช้ข้างต้น แต่ฉันประสบปัญหาเดียวกันนี้และฉันแก้ไขได้ด้วยโซลูชันด้านล่าง

<Button
        android:id="@+id/btnRemove"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/btnEdit"
        android:layout_weight="1"
        android:background="@drawable/btn"
        android:text="@string/remove" 
        android:onClick="btnRemoveClick"
        />

btnRemoveClick Click event

public void btnRemoveClick(View v)
{
    final int position = listviewItem.getPositionForView((View) v.getParent()); 
    listItem.remove(position);
    ItemAdapter.notifyDataSetChanged();

}

วิธีแก้ปัญหาที่น่าสนใจ
sherpya

9

อาจเป็นไปได้ว่าคุณพบวิธีที่จะทำ แต่คุณสามารถโทร

ListView.setItemsCanFocus(true)

และตอนนี้ปุ่มของคุณจะจับโฟกัส


5

ฉันไม่แน่ใจว่าจะเป็นวิธีที่ดีที่สุด แต่ใช้งานได้ดีและรหัสทั้งหมดยังคงอยู่ใน ArrayAdapter ของคุณ

package br.com.fontolan.pessoas.arrayadapter;

import java.util.List;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import br.com.fontolan.pessoas.R;
import br.com.fontolan.pessoas.model.Telefone;

public class TelefoneArrayAdapter extends ArrayAdapter<Telefone> {

private TelefoneArrayAdapter telefoneArrayAdapter = null;
private Context context;
private EditText tipoEditText = null;
private EditText telefoneEditText = null;
private ImageView deleteImageView = null;

public TelefoneArrayAdapter(Context context, List<Telefone> values) {
    super(context, R.layout.telefone_form, values);
    this.telefoneArrayAdapter = this;
    this.context = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.telefone_form, parent, false);

    tipoEditText = (EditText) view.findViewById(R.id.telefone_form_tipo);
    telefoneEditText = (EditText) view.findViewById(R.id.telefone_form_telefone);
    deleteImageView = (ImageView) view.findViewById(R.id.telefone_form_delete_image);

    final int i = position;
    final Telefone telefone = this.getItem(position);
    tipoEditText.setText(telefone.getTipo());
    telefoneEditText.setText(telefone.getTelefone());

    TextWatcher tipoTextWatcher = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            telefoneArrayAdapter.getItem(i).setTipo(s.toString());
            telefoneArrayAdapter.getItem(i).setIsDirty(true);
        }
    };

    TextWatcher telefoneTextWatcher = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            telefoneArrayAdapter.getItem(i).setTelefone(s.toString());
            telefoneArrayAdapter.getItem(i).setIsDirty(true);
        }
    };

    tipoEditText.addTextChangedListener(tipoTextWatcher);
    telefoneEditText.addTextChangedListener(telefoneTextWatcher);

    deleteImageView.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            telefoneArrayAdapter.remove(telefone);
        }
    });

    return view;
}

}

3

ฉันรู้ว่ามันล่าช้า แต่สิ่งนี้อาจช่วยได้นี่เป็นตัวอย่างวิธีที่ฉันเขียนคลาสอะแดปเตอร์ที่กำหนดเองสำหรับการคลิกที่แตกต่างกัน

 public class CustomAdapter extends BaseAdapter {

    TextView title;
  Button button1,button2;

    public long getItemId(int position) {
        return position;
    }

    public int getCount() {
        return mAlBasicItemsnav.size();  // size of your list array
    }

    public Object getItem(int position) {
        return position;
    }

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

        if (convertView == null) {
            convertView = getLayoutInflater().inflate(R.layout.listnavsub_layout, null, false); // use sublayout which you want to inflate in your each list item
        }

        title = (TextView) convertView.findViewById(R.id.textViewnav); // see you have to find id by using convertView.findViewById 
        title.setText(mAlBasicItemsnav.get(position));
      button1=(Button) convertView.findViewById(R.id.button1);
      button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //your click action 

           // if you have different click action at different positions then
            if(position==0)
              {
                       //click action of 1st list item on button click
        }
           if(position==1)
              {
                       //click action of 2st list item on button click
        }
    });

 // similarly for button 2

   button2=(Button) convertView.findViewById(R.id.button2);
      button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //your click action 

    });



        return convertView;
    }
}

-4

โซลูชันแพลตฟอร์มสำหรับการนำไปใช้นี้ใช้เมนูบริบทที่แสดงบนการกดแบบยาวหรือไม่

ผู้เขียนคำถามทราบถึงเมนูบริบทหรือไม่ การวางซ้อนปุ่มใน listview มีผลกระทบด้านประสิทธิภาพจะทำให้ยุ่งเหยิง UI ของคุณและละเมิดการออกแบบ UI ที่แนะนำสำหรับแพลตฟอร์ม

บน flipside; เมนูบริบท - โดยธรรมชาติของการไม่มีตัวแทนแฝง - ไม่ชัดเจนสำหรับผู้ใช้ พิจารณาการบันทึกพฤติกรรมหรือไม่

คำแนะนำนี้จะช่วยให้คุณเริ่มต้นได้ดี

http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/

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