32

私はマテリアル デザイン アプリに取り組んでいます。私が実装したい機能の 1 つは、ある種の投票です。ユーザーがリストの要素をクリックすると、次のような永続的な下部シート ダイアログが表示されます。

質問と 3 つのボタンを備えた永続的な下部シート ダイアログ。

次に、ユーザーがいずれかのボタンをクリックすると、このダイアログが消えてモーダル ボトム シート ダイアログが表示され、最初にクリックされたリスト項目に関する詳細情報がユーザーに提供されます。次のようになります。

ボタンの 1 つがクリックされた後に表示されるモーダル ボトム シート ダイアログ

AppCompat ダイアログに関する情報を読んでも、BottomSheetDialog と BottomSheetDialogFragment についての明確な説明と、それらを正しく使用する方法が見つかりません。だから、私の質問は次のとおりです。

  1. それらはどのように異なり、それぞれの場合にどちらを使用する必要がありますか?
  2. ダイアログでどのボタンが押されたかについてアクティビティでデータを取得する方法は?
  3. それらの使用に関する実装またはチュートリアルのコードへのリンクはありますか?
4

2 に答える 2

20

最後に、解決策を見つけて動作します。私が何か間違ったことをしているなら教えてください。基本的にはこのガイドの DialogFragment と同じように機能しますが、私は少し違うやり方をしています。

1) DialogFragment と Dialog の違いと同じで、どちらもモーダルです。永続的なダイアログが必要な場合は、代わりに BottomSheetBehaviour を使用してください(私のアプリでは両方のダイアログをモーダルにする必要があることがわかりました)。

2) 最初に 3 番目の質問に何らかのコードで答える必要があり、それから 2 番目の質問に簡単に答えることができます。

3) FragmentRandomEventPoll と名付けた新しいpublic classを作成します。extends BottomSheetDialogFragmentここで実装しなければならないことが 2 つあります。

  • メソッドをオーバーライドしonCreateViewます。アクティビティのメソッドとほぼ同じですが、onCreateインフレートするビューを返す点が異なります。

    // We will need it later
    private static String headerItem;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                 Bundle savedInstanceState) {
    
    View v = inflater.inflate(R.layout.fragment_random_event_poll, container, false);
        header = (TextView) v.findViewById(R.id.uRnd_fragment_bottom_sheet_poll_header);
        skip = (Button) v.findViewById(R.id.uRnd_fragment_bottom_sheet_button_skip);
        header.setText(...);
    
        // I implemented View.OnClickListener interface in my class
        skip.setOnClickListener(this);
        return v;
    }
    
  • 必要なデータを渡してこのクラスの新しいインスタンスを取得できる静的メソッド (おそらく、通常のコンストラクターを使用することもできたので、もう少し実験する必要があります)。URandomEventListItemデータモデルクラスです。

    public static FragmentRandomEventPoll newInstance(URandomEventListItem item) {
        FragmentRandomEventPoll fragment = new FragmentRandomEventPoll();
        headerItem = item.getHeader();
        return fragment;
    } 
    

2) アクティビティまたはその他の場所で入力イベントを取得するには、必要なメソッドを使用してインターフェイスを定義し、そのインスタンスのセッター メソッドを作成します。

private PollButtonClickListener listener;

public void setListener(PollButtonClickListener listener) {
    this.listener = listener;
}

public interface PollButtonClickListener {
    void onAnyButtonClick(Object data)
}

そして、データを取得したい場所で (「dialog_event_poll」タグがレイアウトで指定されました):

FragmentRandomEventPoll poll = FragmentRandomEventPoll.newInstance(events.get(id));
poll.setListener(new FragmentRandomEventPoll.PollButtonClickListener() {
        @Override
        public void onAnyButtonClick(Object data) {
            // Do what you want with your data
        }
    });
    poll.show(getSupportFragmentManager(), "dialog_event_poll");
}

不明な点があれば、私のプロジェクト ファイルはGithubで見つけることができます。

于 2016-05-01T22:58:24.557 に答える
2

DialogFragment/BottomSheetDialogFragment からのイベント処理について。

多くのアクティビティを伴うアプリケーションの場合、この方法は優れています。

context as MyDialogFragmentListener

しかし、単一のアクティビティと複数のフラグメントを持つアプリケーションに問題があります。多くのフラグメントが存在する可能性があるため、メイン アクティビティを通じてすべてのイベントを必要なフラグメントに転送することは、非常に悪いオプションのように思えます。したがって、私はこれを行うことにしました:

  private inline fun <reified T> findListeners(): ArrayList<T> {
    val listeners = ArrayList<T>()
    context?.let {
        if (it is T) listeners.add(it)
        if (it is AppCompatActivity) {
            it.supportFragmentManager.fragments.forEach { fragment ->
                if (fragment is T) listeners.add(fragment)
                fragment.childFragmentManager.fragments.forEach { childFragment ->
                    if (childFragment is T) listeners.add(childFragment)
                }
            }
        }
    }
    return listeners
}

DialogFragment のコード:

  private val listeners by lazy { findListeners<MyDialogFragmentListener>() }

もちろん、フラグメントには他のフラグメントを好きなだけ含めることができ、おそらく再帰によってチェックする必要がありますが、私の場合、これは不要です。

于 2021-02-09T11:59:27.103 に答える