web-dev-qa-db-ja.com

ConstraintLayoutのグループを使用して、複数のビューでクリックイベントをリッスンします

基本的に、ConstraintLayout内の複数のビューに単一のOnClickListenerをアタッチしたいと思います。

ConstraintLayoutに移行する前に、リスナーを追加できる1つのレイアウト内のビュー。現在、それらはConstraintLayoutのすぐ下にある他のビューと同じレイヤー上にあります。

ビューをAndroid.support.constraint.Groupに追加してみて、OnClickListenerをプログラムで追加しました。

group.setOnClickListener {
    Log.d("OnClick", "groupClickListener triggered")
}

ただし、これはConstraintLayoutバージョン1.1.0-beta2の時点では機能していないようです

私は何か間違ったことをしましたか?この動作を達成する方法はありますか、またはリスナーを各単一ビューにアタッチする必要がありますか?

21
Endzeit

GroupConstraintLayoutは、見知らぬビューの緩やかな関連付けです。これはViewGroupではないため、ビューがViewGroupにあるときのように、シングルクリックリスナーを使用することはできません。

別の方法として、コード内のGroupのメンバーであるIDのリストを取得し、クリックリスナーを明示的に設定できます。 (この機能に関する公式ドキュメントは見つかりませんでしたが、コードリリースより遅れていると思います。) getReferencedIdshere のドキュメントを参照してください。

Java:

    Group group = findViewById(R.id.group);
    int refIds[] = group.getReferencedIds();
    for (int id : refIds) {
        findViewById(id).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // your code here.
            }
        });
    }

Kotlinでは、そのための拡張機能を構築できます。

コトリン:

    fun Group.setAllOnClickListener(listener: View.OnClickListener?) {
        referencedIds.forEach { id ->
            rootView.findViewById<View>(id).setOnClickListener(listener)
        }
    }

次に、グループで関数を呼び出します。

    group.setAllOnClickListener(View.OnClickListener {
        // code to perform on click event
    })

更新

参照されたIDは、2.0.0-beta1以前ではありますが、2.0.0-beta2ですぐには使用できません。上記のコードを「投稿」して、レイアウト後に参照IDを取得します。このような何かが動作します。

class MainActivity : AppCompatActivity() {
    fun Group.setAllOnClickListener(listener: View.OnClickListener?) {
        referencedIds.forEach { id ->
            rootView.findViewById<View>(id).setOnClickListener(listener)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Referenced ids are not available here but become available post-layout.
        layout.post {
            group.setAllOnClickListener(object : View.OnClickListener {
                override fun onClick(v: View) {
                    val text = (v as Button).text
                    Toast.makeText(this@MainActivity, text, Toast.LENGTH_SHORT).show()
                }
            })
        }
    }
}

これは2.0.0-beta2より前のリリースで機能するはずです。したがって、これを行うことができ、バージョンチェックを行う必要はありません。

38
Cheticamp

Kotlinユーザーの受け入れられた答えを補完するために、拡張関数を作成し、ラムダを受け入れてAPIのように感じますgroup.addOnClickListener { }

拡張機能を作成します。

fun Group.addOnClickListener(listener: (view: View) -> Unit) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener(listener)
    }
}

使用法:

group.addOnClickListener { v ->
    Log.d("GroupExt", v)
}
6
Rodrigo Queiroz

複数のビューからクリックイベントをリッスンするより良い方法は、必要なすべてのビューの上にコンテナーとして透明なビューを追加することです。このビューは、クリックを実行するために必要なすべてのビューの最後(つまり最上部)になければなりません。

サンプルコンテナビュー:

<View
   Android:id="@+id/view_container"
   Android:layout_width="0dp"
   Android:layout_height="0dp"
   app:layout_constraintBottom_toBottomOf="@+id/view_bottom"
   app:layout_constraintEnd_toEndOf="@+id/end_view_guideline"
   app:layout_constraintStart_toStartOf="@+id/start_view_guideline"
   app:layout_constraintTop_toTopOf="parent"/>

上記のサンプルには、その中に4つの制約境界がすべて含まれています。一緒に聞くためのビューを追加できます。ビューであるため、リップル効果など、何でもできます。

5
Vitthalk

拡張方法は素晴らしいですが、次のように変更することでさらに改善できます

fun Group.setAllOnClickListener(listener: (View) -> Unit) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener(listener)
    }
}

呼び出しは次のようになります

group.setAllOnClickListener {
    // code to perform on click event
}

これで、View.OnClickListenerを明示的に定義する必要がなくなりました。

このようにGroupOnClickLitenerの独自のインターフェイスを定義することもできます

interface GroupOnClickListener {
    fun onClick(group: Group)
}

そして、このような拡張メソッドを定義します

fun Group.setAllOnClickListener(listener: GroupOnClickListener) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener { listener.onClick(this)}
    }
}

そして、このように使用します

groupOne.setAllOnClickListener(this)
groupTwo.setAllOnClickListener(this)
groupThree.setAllOnClickListener(this)

override fun onClick(group: Group) {
    when(group.id){
        R.id.group1 -> //code for group1
        R.id.group2 -> //code for group2
        R.id.group3 -> //code for group3
        else -> throw IllegalArgumentException("wrong group id")
    }
}

すべてのビューのリスナーとして1つのオブジェクトのみを使用するため、ビューの数が多い場合は、2番目のアプローチのパフォーマンスが向上します。

2
Reza A. Ahmadi

Vitthalkの答え の一般的なアプローチが好きですが、1つの大きな欠点と2つの小さな欠点があると思います。

  1. 単一ビューの動的な位置変更は考慮されません

  2. グループの一部ではないビューのクリックを登録する場合があります

  3. このかなり一般的な問題に対する一般的な解決策ではありません

2番目のポイントの解決策についてはわかりませんが、1番目と3番目のポイントに対する解決策は明らかに簡単です。


1。グループ内の要素の会計位置の変更

これは実際にはかなり簡単です。制約レイアウトのツールセットを使用して、透明なビューのエッジを調整できます。 バリア を使用して、グループ内の任意のビューの左端、右端などの位置を受け取ります。次に、具体的なビューの代わりに透明なビューをバリアに合わせて調整できます。

3。一般的なソリューション

Kotlinを使用すると、Group-Classを拡張して、上記のようにViewにClickListenerを追加するメソッドを含めることができます。このメソッドは、グループのすべての子に注意を払ってレイアウトにバリアを追加するだけです。透明なビューはバリアに揃えられ、ClickListenerを後者に登録します。

この方法では、グループでメソッドを呼び出すだけでよく、この動作が必要になるたびにビューをレイアウトに手動で追加する必要はありません。

1
Endzeit