Android: Birden çok tıklanabilir düğmeli ListView öğeleri


182

ListViewListedeki her öğenin bir TextView ve iki farklı Düğme içerdiği bir yerim var . Bunun gibi bir şey:

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

Bu kod ile OnItemClickListenertüm öğe için bir oluşturabilirsiniz :

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

        }

    }
});

Ancak, tüm öğenin tıklanabilir olmasını istemiyorum, ancak her liste öğesinin yalnızca iki düğmesi var.

Benim sorum şu, bu iki düğme için bir onClickListener'ı aşağıdaki parametrelerle nasıl uygularım:

  • int button (öğenin hangi düğmesi tıklanmışsa)
  • int position (listedeki düğme tıklamasının gerçekleştiği öğedir)

Güncelleme: Aşağıdaki cevabımda açıklandığı gibi bir çözüm buldum. Şimdi dokunmatik ekran üzerinden düğmeye tıklayabilir / dokunabilirim. Ancak, topunu elle seçemiyorum. Her zaman tüm liste öğesini seçer ve hatta Sette olsa düğmeleri görmezden sonraki liste öğesine doğrudan gitmektedir .setFocusable(true)ve setClickable(true)düğmelerin getView().

Ayrıca bu kodu özel liste bağdaştırıcıma ekledim:

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

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

Bu, artık hiçbir liste öğesinin seçilememesine neden olur. Ancak, iç içe düğmelerin seçilebilir olmasına yardımcı olmadı.

Bir fikriniz var mı?


Bunlara hala ihtiyaç var mı?
Stuart Axon

BaseAdapter koduna bakarsanız, areAllItemsEnabled () ve isEnabled () öğelerinin sadece true olarak kodlandığını görürsünüz, bu da onları mantık olmadan basit yer tutucular yapar.
Artem Russakovskii

SimpleCursorAdapter kullanmak istersem ne yapmalıyım?
oratis

Yanıtlar:


150

Bunun çözümü aslında düşündüğümden daha kolay. Özel bağdaştırıcınızın getView()yöntemine, kullandığınız düğmeler için bir setOnClickListener () ekleyebilirsiniz .

Düğme ile bağlantılı her veri ile ilave edilmesi gerekir myButton.setTag()içinde getView()ve üzerinden OnClickListener erişilebilirview.getTag()

Blogumda bir eğitim olarak ayrıntılı bir çözüm yayınladım .



curItem.url sorgusundan ne kadar iyi elde ettiniz, daha spesifik olur musunuz?
oratis

1
Teşekkürler znq, Bu benim için çok yararlı oldu ... Bir paket zaman kazandım.
Nandagopal T

11:39'da bu konuşmayı izleyin: mükemmel bir örnek var: youtu.be/wDBM6wVEO70?t=11m39s Öyleyse @Znq ne diyorsa yapın ... setTag () düğmenin onClickListener () yöntemi. Teşekkür ederim!
Shehaaz

12
SO'nun kendisinde cevapların olması harika olur ve başka bir sayfaya işaret etmez. Blog bağlantısı öldü!
gsb

63

Bu bir ek @ znq cevabı ...

Tıklanan bir öğenin satır konumunu bilmek istediğiniz ve satırdaki hangi görünümün tıklandığını bilmek istediğiniz birçok durum vardır. Bu, tablet kullanıcı arayüzlerinde çok daha önemli olacak.

Bunu aşağıdaki özel adaptörle yapabilirsiniz:

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
ya da böyle bir şey kullanabilirsiniz ListView mListView = (ListView) v.getParent (). getParent ();
max4ever

1
Bağdaştırıcıyı ayrı bir sınıfta kullanırsam konumu nasıl alabilirim? Ben sadece OnClickListener içindeki konumu kullandım, böyle bir şey gibi_c.get (pozisyon). Bağdaştırıcının getView yönteminde son konuma getirilmesini önerir. Bu pozisyonu değiştirirsem, aldım lisview tüm öğeler için aynıdır. Bunu nasıl çözeceğimi önerebilir misin?
Manikandan

Çünkü getView yönteminin position parametresini kullandığınızda, en son oluşturulan ancak tıklattığınız listenin öğesinin konumunu size verir
Archie.bpgc 20:12

@Manikandan: Bağdaştırıcının getView () yöntemini kullanıyorsanız, yöntem parametrelerinde size zaten konum verilmiş demektir. Bu durumda, konum bilgisini saklamak için setTag () gibi bir şey kullanabilirsiniz.
greg7gkb

1
Kodumu uygulamamda kullanıyorum, ancak gecikme sonrasında veya liste görünümünü kaydırmaya çalıştığımda click olayı çağrılıyor. Bunun neden olduğu hakkında bir fikrin var mı?
Abdullah Umer

22

Gelecekteki okuyucular için:

Hareket topunu kullanarak düğmeleri manuel olarak seçmek için:

myListView.setItemsCanFocus(true);

Tüm liste öğelerine odaklanmayı devre dışı bırakmak için:

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

Benim için iyi çalışıyor, dokunmatik ekranlı düğmelere tıklayabilirim ve aynı zamanda tuş takımını kullanarak bir tıklamaya odaklanır


2
Sadece bu bana yardımcı oldu! Çok teşekkür ederim!
Onur

Bir ExpandableListView hakkında, ben öğede birden çok görünüm var, ben sadece çocuk tıklanabilir görünümleri istiyorum, teşekkürler.
twlkyao

12

Yukarıdaki kullanıcılardan daha fazla deneyimim yok ama aynı sorunla karşılaştım ve bunu aşağıdaki Çözüm ile çözdüm

<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 etkinliği

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

}

ilginç çözüm
sherpya

9

Muhtemelen nasıl yapacağınızı buldunuz, ancak arayabilirsiniz

ListView.setItemsCanFocus(true)

ve şimdi düğmeleriniz odaklanacak


5

En iyi yolu hakkında emin değilim, ama iyi çalışıyor ve tüm kod ArrayAdapter içinde kalır.

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

Geç olduğunu biliyorum ama bu yardımcı olabilir, bu nasıl farklı tıklama eylemleri için özel adaptör sınıfı yazmak bir örnektir

 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

Bu uygulamanın platform çözümü, uzun bir basışta gösterilen bir bağlam menüsü kullanmıyor mu?

Soru yazarı bağlam menülerinin farkında mı? Liste görünümünde düğmelerin yığılmasının performans etkileri vardır, kullanıcı arayüzünüzü dağıtır ve platform için önerilen kullanıcı arayüzü tasarımını ihlal eder.

Diğer tarafda; bağlam menüleri - pasif bir temsile sahip olmamasının doğası gereği - son kullanıcı için açık değildir. Davranışı belgelemeyi düşünüyor musunuz?

Bu kılavuz size iyi bir başlangıç ​​yapmalıdır.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.