Android Fragments 将片段添加到列表视图项

p1tboqfb  于 2023-04-06  发布在  Android
关注(0)|答案(6)|浏览(263)

我希望列表视图中的每一项都有一个片段,因为我想分离出一些逻辑。我为每一项使用了一个视图保持器。如果视图不存在,我就创建一个新的片段并将其添加到容器中。

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

同样,对于每一项,我调用保持器.mMyFragment.setUi(dataSource,position)来根据数据源和位置设置片段的UI。
我遇到的问题是我在fragment类的onCreateView方法中初始化了fragment的UI元素,但是当我将fragment添加到item时没有调用它。所以后来当我调用setUi()时,它使用了fragment中的一些UI元素,它抱怨了一个NullPointerException。有人有建议吗?谢谢!

kpbpu008

kpbpu0081#

有解决方案”。
问题是,你***不能像上面的代码那样,在listview中直接向容器***(FrameLayout)添加相同“id”的片段。

技巧是,创建“LinearLayout”的listview(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);
    }
}
nwlls2ji

nwlls2ji2#

我希望列表视图中的每一项都有一个片段,因为我想分离出一些逻辑。
你不能使用fragment作为列表项视图,因为API不允许你-ViewFragment甚至没有相关性,所以你不可能这样使用它。创建自定义视图并使用适配器getViewTypeCountgetView来使用不同的列表项行为。
片段由Activity的FragmentManager或其他Fragment子FragmentManager管理;而列表项视图由ListView & ListAdapter管理。您可以在Fragments中使用ListView,但不能反过来。

slmsl1lt

slmsl1lt3#

一个简单的方法。一个问题:你应该存储添加恢复片段状态。

holder.mMyFragment = new MyFragment(mActivity, this);
int id = View.generateViewId();
findViewByTag("abc").setId(id);
mActivity.getSupportFragmentManager().beginTransaction().add(id, holder.mMyFragment).commit();
bpzcxfmw

bpzcxfmw4#

你好,我也遇到了同样的问题,我找到了解决的方法。
我的问题和你类似:
“我希望列表视图中的每个项目都有一个片段,因为我想分离出一些逻辑”
在我的应用程序中,我必须给予垂直(listView)和水平(ViewPager)模式显示自定义项的选项。此外,我必须处理18个自定义项,每个项都有不同的逻辑,所以最好的方法是重用我在ListView中用于ViewPager的片段。
我得到了它,但不是你尝试的方式,我的意思是,我用我的片段,如“ViewHolders”:
1.在每个片段中定义类的变量等片段的小部件。
1.创建自定义ArrayAdapter并覆盖:getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent)
getView中,我检查了在“膨胀”相应的XML之前需要什么样的布局,创建一个片段,将XML中的小部件分配给片段(使用rootView.findViewById),并使用新片段设置“标签”。
在这一点上,你可以看到ListView中的片段从未附加到Activity,但你得到了你想要的:逻辑分布在几个部分和所有好处的列表视图(重用行,滚动等)。
如果你需要,我可以张贴我的代码的一部分,但你必须处理“西班牙式英语”;).

已更新

所有的问题都是因为当你创建一个要与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中获取给定位置的对象,重用一个“viewholder”并填充数据。下面是我的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

mbyulnm0

mbyulnm05#

Android文档:“Fragment表示Activity中的一个行为或用户界面的一部分。您可以将多个Fragment合并到单个Activity中,以构建多窗格UI,并在多个Activity中重用一个Fragment。”
对于您的Activity,您是否希望添加2个片段,其中第一个片段显示listView(= ListFragment),另一个片段位于右侧,仅当用户单击项目(来自第一个片段或listView)时才显示?

nx7onnlm

nx7onnlm6#

除了使用ListFragment,你还可以使用RecyclerView,Android有相关文档:

https://developer.android.com/training/basics/fragments/creating.html#AddInLayout

相关问题