質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

AndroidのListViewにて、List上に配置したボタンのイベントを取得したい。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,673

lereve

score 12

 前提・実現したいこと

[前提]
趣味でプログラムを触ったことがある程度の初心者です。
質問内容はあまりに根本的な内容になるかとは思いますが、
参考本やHPに書かれている内容ではなかなか理解できず困っています。
是非、ご教授いただきたく思います。

[実現したいこと]
Androidの画面上にListViewを配置し、それぞれの行にTextViewとButtonを配置、
このButtonが押された時の処理を書きたいと思っています。(チェックリストのイメージです。)

 発生している課題

参考書やHPを参考にし、コードを写経してみたものの、ボタンのイベントが取得できておりません。

現在クラスは3つあり、いつものMainActivityと
ListViewの各項目用のListItemクラス、
ArrayAdapterを継承したListAdapterクラスがあります。

各項目の場所を把握したい(〇列目のOKボタンが押された、など)のですが、
こういった場合はどこにどのような処理を書けばいいのでしょうか。

よろしくお願いします。

 追記・修正

MainActivityのコードがListViewのコードになってしまっていました。
訂正しました。
申し訳ありませんでした。

ListAdapter のgetViewメソッド内にリスナーが抜けておりましたので追加しましたところ、
Button okButton =(Button) convertView.findViewById(R.id.ok_Button);
の部分でぬるぽが発生します。

 画面写真

イメージ説明

 コード

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // レイアウトからリストビューを取得
        ListView listView = (ListView)findViewById(R.id.listview);

        // リストビューに表示する要素を設定
        ArrayList<ListItem> listItems = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            ListItem item = new ListItem(i + 1, "sample text", 0);
            listItems.add(item);
        }

        // 出力結果をリストビューに表示
        ListAdapter adapter = new ListAdapter(this, R.layout.list_item, listItems);
        listView.setAdapter(adapter);

        // タップ時のイベントを追加
        listView.setOnItemClickListener(onItemClickListener);

    }

    private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(MainActivity.this, "テスト", Toast.LENGTH_LONG).show();

            // タップしたアイテムの取得
            ListView listView = (ListView)parent;
            ListItem item = (ListItem)listView.getItemAtPosition(position);  // ListItemにキャスト

            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("Tap No. " + String.valueOf(position));
            builder.setMessage(item.getQuestionContent());
            builder.show();
        }
    };

}

ListItem

public class ListItem {
    private int mQuestionNumber = 0;
    private String mQuestionContent = "";
    private int mStatus = 0;

    public ListItem(int questionNumber, String questionContent, int status){
        mQuestionNumber = questionNumber;
        mQuestionContent = questionContent;
        mStatus = status;
    }

    public void setQuestionNumber(int questionNumber){
        mQuestionNumber = questionNumber;
    }

    public void setQuestionContext(String questionContext){
        mQuestionContent = questionContext;
    }

    public void setStatus(int status){
        mStatus = status;
    }
    public int getQuestionNumber(){
        return mQuestionNumber;
    }
    public String getQuestionContent(){
        return mQuestionContent;
    }
    public int getStatus(){
        return mStatus;
    }

}

ListAdapter

public class ListAdapter extends ArrayAdapter<ListItem> {

    private int mResource;
    private List<ListItem> mItems;
    private LayoutInflater mInflater;

    public ListAdapter(Context context, int resource, List<ListItem> items){
        super(context, resource, items);

        mResource = resource;
        mItems = items;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        if (convertView != null) {
            view = convertView;
        }
        else {
            view = mInflater.inflate(mResource, null);
        }

        // リストビューに表示する要素を取得
        ListItem item = mItems.get(position);

        Button okButton =(Button) convertView.findViewById(R.id.ok_Button);
        okButton.setOnClickListener(new OK_Listener());

        Button ngButton =(Button) convertView.findViewById(R.id.ng_Button);
        ngButton.setOnClickListener(new NG_Listener());

        Button noneButton =(Button) convertView.findViewById(R.id.none_Button);
        noneButton.setOnClickListener(new NONE_Listener());

        Button commentButton =(Button) convertView.findViewById(R.id.comment_Button);
        commentButton.setOnClickListener(new Comment_Listener());

        // QuestionNumberに番号を設定
        TextView questionNumber = (TextView)view.findViewById(R.id.questionNumber);
        questionNumber.setText(Integer.toString(item.getQuestionNumber()));

        // QuestionContextに番号を設定
        TextView questionContext = (TextView)view.findViewById(R.id.questionContext);
        questionContext.setText(item.getQuestionContent());

        return view;
    }
    //okボタンのリスナー
    class OK_Listener implements View.OnClickListener {
        public void onClick(View v){
            Log.v("**********", "OK_Button");
        }
    }

    //ngボタンのリスナー
    class NG_Listener implements View.OnClickListener {
        public void onClick(View v){
            Log.v("**********", "NG_Button");
        }
    }

    //noneボタンのリスナー
    class NONE_Listener implements View.OnClickListener {
        public void onClick(View v){
            Log.v("**********", "NONEK_Button");
        }
    }

    //commentボタンのリスナー
    class Comment_Listener implements View.OnClickListener {
        public void onClick(View v){
            Log.v("**********", "Comment_Button");
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kakajika

    2018/03/16 00:03

    MainActivityのところにListAdapterのソースコードが貼られているようなので、正しいものに変更していただけますか?

    キャンセル

  • lereve

    2018/03/19 08:44

    kakajika様 ご指摘いただきありがとうございます。質問文を訂正いたしました。よろしくお願いします。

    キャンセル

回答 2

checkベストアンサー

+2

MainActivity側でイベントを受け取りたいパターンを想定して回答いたします。

まず、今回のようなケースではAndroid標準のリスナーだけでやろうとすると少々不足する部分があるので、自分でリスナーを定義して通知の仕組みを実装されることをオススメします。

欲しいデータは ◯列目の〜ボタン ですから、それをイメージしてリスナーを定義してみましょう。ボタンが何のボタンであるかの判定には、Viewのidを使います。

// 定義の例
interface ListItemButtonClickListener {
    public void onItemButtonClick(int position, View view);
}

このリスナーをListAdapterの生成時に渡すようにして、各ボタンのクリック時にリスナーの onItemButtonClick を呼び出すことでイベントを知らせることができます。

// 実装例(関係ないところは省略しています)
public class ListAdapter extends ArrayAdapter<ListItem> {

    private ListItemButtonClickListener mListener;

    public ListAdapter(Context context, int resource, List<ListItem> items, ListItemButtonClickListener listener){
        ...
        mListener = listener;
    }

    // OnClickListener内で使うためにpositionはfinal intにする
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view;

        ...

        view.findViewById(R.id.ok_Button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v){
                // onButtonClickを呼び出してmListenerにイベントを知らせる(以下同様)
                mListener.onItemButtonClick(position, v)
            }
        });

        view.findViewById(R.id.ng_Button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v){
                mListener.onItemButtonClick(position, v)
            }
        });

        view.findViewById(R.id.done_Button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v){
                mListener.onItemButtonClick(position, v)
            }
        });

        view.findViewById(R.id.comment_Button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v){
                mListener.onItemButtonClick(position, v)
            }
        });

        ...
        return view;
    }
}

あとは、MainActivity側で ListItemButtonClickListener を実装してListAdapterの生成時に渡してあげればOKです。

// 実装例
ListAdapter adapter = new ListAdapter(this, R.layout.list_item, listItems, new ListItemButtonClickListener() {
    public void onItemButtonClick(int position, View view) {
        switch (view.getId()) {
            case R.id.ok_button:
                // OKボタンが押された時の処理(以下同様)
                break;
            case R.id.ng_button:
                break;
            case R.id.done_button:
                break;
            case R.id.comment_button:
                break;
        }
    }
});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/19 13:14

    kakajika様
    自分でリスナーを定義…そういう方法もありましたね!
    意図する動作を実現させることが出来ました。
    大変参考になりました。
    ありがとうございました。

    キャンセル

0

ArrayAdapterのgetviewでボタンの定義をしてないからじゃないですか?

自分も初心者なんでよくわかりませんが、

https://qiita.com/maromaro3721/items/6ac3cba4f090662adabf

だとやってるけどあなたのやつにはないので...

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/19 09:02

    rainysk様
    ご指摘ありがとうございます。getView内に
    Button okButton =(Button) convertView.findViewById(R.id.ok_Button);
    okButton.setOnClickListener(new OK_Listener());
    を追加し、
    //okボタンのリスナー
    class OK_Listener implements View.OnClickListener {
    public void onClick(View v){
    Log.v("**********", "OK_Button");
    }
    }
    を追加しましたところ、
    Button okButton =(Button) convertView.findViewById(R.id.ok_Button);
    の部分でぬるぽが出るようです。

    キャンセル

  • 2018/03/19 13:09

    `convertView` はnullになっている可能性がありますから、convertViewがnullかどうかをチェックしてnullなら新規にinflateしている `view` に対してfindViewByIdを呼ぶようにしましょう。

    キャンセル

  • 2018/03/19 13:17

    kakajika様
    convertViewについての知識量が浅すぎたようです。
    ぬるぽが出るならnullかどうかチェックすればいい、ところまでは自己調査でわかったのですがその後どこにfindViewByIdすればよいかわからず、こちらも大変ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる