Android: Các phần tử ListView có nhiều nút có thể nhấp


182

Tôi có một ListViewphần tử trong danh sách chứa TextView và hai Nút khác nhau. Một cái gì đó như thế này:

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

Với mã này tôi có thể tạo một OnItemClickListenercho toàn bộ mục:

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

        }

    }
});

Tuy nhiên, tôi không muốn toàn bộ mục có thể nhấp được mà chỉ có hai nút của mỗi thành phần danh sách.

Vì vậy, câu hỏi của tôi là, làm cách nào để triển khai onClickListener cho hai nút này với các tham số sau:

  • int button (nút nào của phần tử đã được nhấp)
  • int position (đó là yếu tố trong danh sách mà việc nhấp vào nút xảy ra)

Cập nhật: Tôi tìm thấy một giải pháp như được mô tả trong câu trả lời của tôi dưới đây. Bây giờ tôi có thể nhấp / chạm vào nút thông qua màn hình cảm ứng. Tuy nhiên, tôi không thể tự chọn nó bằng trackball. Nó luôn chọn toàn bộ mục danh sách và từ đó đi thẳng đến mục danh sách tiếp theo bỏ qua các nút, mặc dù tôi đã đặt .setFocusable(true)setClickable(true)cho các nút trong getView().

Tôi cũng đã thêm mã này vào bộ điều hợp danh sách tùy chỉnh của mình:

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

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

Điều này gây ra rằng không có mục danh sách nào có thể lựa chọn nữa. Nhưng nó không giúp ích gì trong việc lựa chọn các nút lồng nhau.

Bất cứ ai có một ý tưởng?


Những điều này vẫn còn cần thiết?
Stuart Axon

Nếu bạn nhìn vào mã BaseAd CHƯƠNG, bạn sẽ thấy đó là AllItemsEnables () và isEnables () chỉ được mã hóa thành true, biến chúng thành các trình giữ chỗ đơn giản mà không cần logic.
Artem Russakovskii

Điều gì sẽ xảy ra nếu tôi muốn sử dụng SimpleC bổngAd CHƯƠNG? Tôi có phải tạo một bộ điều hợp tùy chỉnh mở rộng chương trình đơn giản không?
oratis

Câu trả lời:


150

Giải pháp cho việc này thực sự dễ dàng hơn tôi nghĩ. Bạn chỉ có thể thêm vào getView()phương thức của bộ điều hợp tùy chỉnh của mình một setOnClickListener () cho các nút bạn đang sử dụng.

Bất kỳ dữ liệu nào được liên kết với nút phải được thêm vào myButton.setTag()trong getView()và có thể được truy cập trong onClickListener thông quaview.getTag()

Tôi đã đăng một giải pháp chi tiết trên blog của tôi như một hướng dẫn.


2
Đã sửa. Cảm ơn bạn đã báo cáo :-)
znq

Làm thế nào exacly bạn có được curItem.url từ truy vấn, bạn sẽ cụ thể hơn?
oratis

1
Cảm ơn znq, Điều đó rất hữu ích cho tôi ... Đã tiết kiệm được một bó thời gian.
Nandagopal T

Xem cuộc nói chuyện này lúc 11:39, có một ví dụ tuyệt vời: youtu.be/wDBM6wVEO70?t=11m39s Sau đó hãy làm những gì @znq nói ... setTag () khi convertView == null và thực hiện getTag () trong onClick () phương thức của nút onClickListener (). Cảm ơn bạn!
Shehaaz

12
sẽ rất tuyệt nếu có câu trả lời trong chính SO và không trỏ đến một số trang khác. Liên kết blog đã chết!
gsb

63

Đây là loại câu trả lời của @ znq ...

Có nhiều trường hợp bạn muốn biết vị trí hàng cho một mục được nhấp VÀ bạn muốn biết chế độ xem nào trong hàng đã được gõ. Điều này sẽ quan trọng hơn rất nhiều trong giao diện người dùng máy tính bảng.

Bạn có thể làm điều này với bộ điều hợp tùy chỉnh sau:

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
hoặc bạn cũng có thể sử dụng một cái gì đó như ListView mListView = (ListView) v.getParent (). getParent ();
tối đa

1
Làm thế nào tôi có thể có được vị trí nếu tôi sử dụng bộ chuyển đổi trong một lớp riêng biệt. Tôi chỉ đơn giản sử dụng vị trí bên trong OnClickListener, một cái gì đó giống như like_c.get (vị trí) này. Nó đề nghị làm cho vị trí cuối cùng trong phương thức getView của bộ chuyển đổi. Nếu tôi thực hiện thay đổi vị trí tôi nhận được là giống nhau cho tất cả các mục trong lisview. Bạn có thể gợi ý cho tôi cách giải quyết điều này.
Manikandan

Đó là bởi vì khi bạn sử dụng tham số vị trí của phương thức getView, nó cung cấp cho bạn vị trí của mục trong danh sách được tạo gần đây nhất nhưng không phải là mục bạn đã nhấp
Archie.bpgc

@Manikandan: Nếu bạn đang sử dụng phương thức getView () của bộ điều hợp thì bạn đã có vị trí được chuyển cho bạn trong thông số phương thức. Trong trường hợp đó, bạn có thể sử dụng cái gì đó như setTag () để lưu trữ thông tin vị trí.
greg7gkb

1
Tôi đang sử dụng mã của bạn trong ứng dụng của mình nhưng sự kiện nhấp được gọi sau khi trì hoãn hoặc khi tôi cố gắng cuộn listview. Có ý kiến ​​giải thích tại sao điều này lại xảy ra không?
Abdullah Umer

22

Dành cho độc giả tương lai:

Để chọn thủ công các nút có trackball, hãy sử dụng:

myListView.setItemsCanFocus(true);

Và để vô hiệu hóa tập trung vào toàn bộ các mục danh sách:

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

Nó hoạt động tốt với tôi, tôi có thể nhấp vào các nút bằng màn hình cảm ứng và cũng có thể tập trung vào một lần nhấp bằng bàn phím


2
Chỉ có điều này đã giúp tôi! Cảm ơn bạn rất nhiều!
Onur

Điều gì về một ExpandableListView, tôi có nhiều khung nhìn trong mục này, tôi chỉ muốn các khung nhìn trong con có thể nhấp, cảm ơn.
twlkyao

12

Tôi không có nhiều kinh nghiệm hơn những người dùng ở trên nhưng tôi đã gặp phải vấn đề tương tự và tôi đã giải quyết vấn đề này với Giải pháp bên dưới

<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"
        />

sự kiện Click btnRemoveClick

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

}

giải pháp thú vị
sherpya

9

Có lẽ bạn đã tìm thấy cách để làm điều đó, nhưng bạn có thể gọi

ListView.setItemsCanFocus(true)

và bây giờ các nút của bạn sẽ tập trung


5

Tôi không chắc chắn về cách tốt nhất, nhưng hoạt động tốt và tất cả các mã vẫn nằm trong ArrayAd CHƯƠNG của bạn.

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

Tôi biết là muộn nhưng điều này có thể giúp ích, đây là một ví dụ về cách tôi viết lớp bộ điều hợp tùy chỉnh cho các hành động nhấp khác nhau

 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

Không phải là giải pháp nền tảng cho việc triển khai này để sử dụng menu ngữ cảnh hiển thị trên báo chí dài sao?

Là tác giả câu hỏi nhận thức về các menu ngữ cảnh? Việc sắp xếp các nút trong một listview có ý nghĩa về hiệu suất, sẽ làm lộn xộn UI của bạn và vi phạm thiết kế UI được đề xuất cho nền tảng.

Trên flipside; menu ngữ cảnh - về bản chất là không có biểu diễn thụ động - không rõ ràng đối với người dùng cuối. Xem xét tài liệu về hành vi?

Hướng dẫn này sẽ cung cấp cho bạn một khởi đầu tốt.

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

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.