11

いくつかのロジックを分離したいので、リストビュー内の各アイテムのフラグメントが必要です。各アイテムにビューホルダーを使用しています。ビューが存在しない場合は、新しいフラグメントを作成してコンテナーに追加します。

holder.mMyFragment = new MyFragment(mActivity, this);
mActivity.getSupportFragmentManager().beginTransaction().add(R.id.my_container, holder.mMyFragment).commit();

また、アイテムごとに、holder.mMyFragment.setUi(dataSource, position) を呼び出して、データ ソースと位置に基づいてフラグメントの UI を設定します。

私が抱えている問題は、フラグメント クラスの onCreateView メソッドでフラグメントの UI 要素を初期化することですが、フラグメントをアイテムに追加するときに呼び出されません。そのため、後で一部の UI 要素をフラグメントで使用する setUi() を呼び出すと、NullPointerException が発生します。誰か提案がありますか?ありがとう!

4

6 に答える 6

13

これには「解決策があります」。

問題は、上記のコードで行ったように、リストビューで同じ「id」を使用してフラグメントをコンテナー (FrameLayout) に直接追加できないことです。

コツは、「LinearLayout」のリストビュー(Recyclerview)を作成することです。次に、アダプターで FrameLayout を動的に作成し、それぞれに異なる IDを割り当てます。Fragment を FrameLayout にインフレートし、この FrameLayout を LinearLayout にインフレートします。

@Override
protected void onBindBasicItemView(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof VideoHomeViewHolder) {
        VideoHomeViewHolder videoHomeViewHolder = (VideoHomeViewHolder) holder;
        FrameLayout frameLayout = new FrameLayout(mContext);
        frameLayout.setId(position+1); //since id cannot be zero
        FragmentHelper.popBackStackAndReplace(mFragmentManager, frameLayout.getId(),
                new ShowLatestVideosFragment(mShowLatestVideosItems.get(position)));
        videoHomeViewHolder.linearLayout.addView(frameLayout);
    }
}
于 2016-05-12T10:19:40.890 に答える
3

簡単な方法です。1 つの問題: 追加の復元フラグメントの状態を保存する必要があります。

holder.mMyFragment = new MyFragment(mActivity, this);
int id = View.generateViewId();
findViewByTag("abc").setId(id);
mActivity.getSupportFragmentManager().beginTransaction().add(id, holder.mMyFragment).commit();
于 2016-03-29T09:48:05.330 に答える
2

こんにちは、私は同じ問題に直面していて、それを行う方法を見つけました。
私の問題はあなたに似ていました:

「いくつかのロジックを分離したいので、リストビュー内の各アイテムのフラグメントが必要です」

私のアプリでは、垂直 (listView) および水平 (ViewPager) モードでカスタム項目を表示するオプションを提供する必要があります。さらに、18 個のカスタム アイテムをそれぞれ異なるロジックで処理する必要があったため、ListView で ViewPager に使用していたフラグメントを再利用するのが最善の方法でした。

私はそれを手に入れましたが、あなたが試みていた方法ではありません。つまり、「ViewHolders」のようなフラグメントを使用しました:

  1. 各フラグメントのクラスの変数のようなフラグメントのウィジェットを定義します。
  2. カスタム ArrayAdapter を作成してオーバーライドします。getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent)

それぞれの XML を「インgetViewフレート」する前に必要なレイアウトの種類を確認し、フラグメントを作成し、XML からフラグメントにウィジェットを割り当て (を使用rootView.findViewById)、新しいフラグメントで「タグ」を設定しました。

この時点でわかることは、ListView のフラグメントが Activity にアタッチされていないことですが、必要なものが得られたことです。つまり、いくつかの部分に分散されたロジックと、ListView のすべての利点 (行の再利用、スクロールなど) です。

必要に応じて、コードの一部を投稿できますが、「スパングリッシュ」に対処する必要があります;)。



更新しました

すべての問題は、ViewPager で使用する Fragment を作成するときに、通常、すべての「レイアウト」と「セットアップ」コードがonCreateViewメソッド内にあるためです。

  • 使用するビュー オブジェクトを取得します ( View rootView = inflater.inflate(R.layout.fragment_question_horizontal_container, container, false);)
  • 上記のレイアウトからウィジェットを取得し、動作、フォントなどを定義します: ( answer = (EditText)rootView.findViewById(R.id.answer_question_text);)

この時点まで、奇妙なことは何もありません。
上記の動作でフラグメントを使用する場合は、onCreateView への呼び出しを「エミュレート」し、データを入力して listView に添付する必要があります。

秘訣は次のとおりonCreateViewです。誰が呼び出しているかを気にしないいくつかのメソッドにコードを分割します。私の例onCreateView

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_pregunta_horizontal_container, container, false);

    addAnswerLayout(rootView, R.layout.fragment_pregunta_texto, getActivity());
    setUpComponents(rootView);
    //those 2 methods are about my app logic so I'm not going to talk much about them
    setUpQuestionState(savedInstanceState);
    readSavedAnswer();

    return rootView;
}

public void addAnswerLayout(View rootView, int optionId, Context context) {

    mContext = context;

    RelativeLayout relativeLayout = (RelativeLayout)rootView.findViewById(R.id.pregunta_container);

    LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
    View newView = inflater.inflate(optionId, relativeLayout, false);

    relativeLayout.addView(newView);
}

public void setUpComponents(View rootView) {
    //next line: some heritage that you can ignore
    super.setUpComponents(rootView);

    respuesta = (EditText)rootView.findViewById(R.id.pregunta_respuesta_texto);
    respuesta.setTypeface(UiHelper.getInstance(getActivity()).typeface);
    respuesta.setTextColor(mContext.getResources().getColor(R.color.drs_gris));

    ...
}


次に、リスト ビューの CustomArrayAdapter に移動します。

  • customArrayAdapter を次のように定義しますPreguntasVerticalArrayAdapter extends ArrayAdapter<Pregunta>。「Pregunta」は、上記のロジックを持つ汎用フラグメントです。
  • オーバーライドしgetViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent)ます。

同じ動作にgetView従います。params で指定された位置のオブジェクトを取得し、「ビューホルダー」を再利用してデータを入力します。ここに私のgetView

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

    View rowView = convertView;

    Pregunta pregunta = mData.get(position);

    if (rowView == null)
        rowView = createQuestionUI(pregunta, parent, position);

    fillDataInRow((PreguntaUI)rowView.getTag(), pregunta, position);

    return rowView;
}

private View createPreguntaUI(Pregunta pregunta, ViewGroup parent, int position) {

    View rootView = null;

    LayoutInflater inflater = (mPreguntasVerticalFragment.getActivity()).getLayoutInflater();

    //you can ignore this part of the code ralted to Bundle.
    Bundle args = new Bundle();
    args.putLong(PreguntaUI.PREGUNTAUI_ID, pregunta.getIdpregunta());
    args.putInt(PreguntaUI.PREGUNTAUI_INDEX, position);
    args.putInt(PreguntaUI.PREGUNTAUI_TOTAL_QUESTIONS, getCount());

    //internal method of "pregunta" to know what kind of question it is.
    String tipo = pregunta.getTipo();

    if (tipo.equalsIgnoreCase(PreguntaType.TEXT.toString())) {

        rootView = inflater.inflate(R.layout.fragment_pregunta_vertical_container, parent, false);

        Pregunta_texto pregunta_texto = new Pregunta_texto();
        pregunta_texto.setArguments(args);

        //LOOK AT THIS POINT!!!: I'm calling the same methods that I called in onCreateView fragment's method.
        pregunta_texto.addAnswerLayout(rootView, R.layout.fragment_pregunta_texto,
                mPreguntasVerticalFragment.getActivity());
        pregunta_texto.setUpComponents(rootView);
        pregunta_texto.setUpQuestionState(null);
        pregunta_texto.readSavedAnswer();

        //I'm adding the fragment to reuse it when I can
        rootView.setTag(pregunta_texto);
    }
    else if ...

    return rootView;
}



これですべてです... この時点で、CustomArrayAdapters と Fragments を扱った十分な経験があれば、おそらく理解できます! :D

于 2014-09-14T00:44:50.223 に答える
-1

Android ドキュメントから:「フラグメントは、アクティビティの動作またはユーザー インターフェイスの一部を表します。単一のアクティビティで複数のフラグメントを組み合わせて、マルチペイン UI を構築し、複数のアクティビティでフラグメントを再利用できます。」

あなたのアクティビティのために、最初のフラグメントが listView ( = ListFragmentを表示し、もう 1 つが右側にあり、ユーザーが (最初のフラグメントまたは listView から) アイテムをクリックしたときにのみ表示される) 2 つのフラグメントを追加しますか?

于 2013-09-05T20:42:26.573 に答える