如何使用 BaseAdapter 将子片段添加到 Android 中的片段

How can I add child fragments to a fragment in Android using a BaseAdapter

这张图说明了我的 activity 的复杂性。有多个(在本例中为 3 个)片段层需要动态加载。重复片段是使用 LinearListView 加载的,这是我在此处找到的视图库:https://github.com/frankiesardo/LinearListView。这允许列表像 ListView 一样加载,但避免了在 ScrollView 中包含 ListView 的问题。

下面是一些示例代码:

line_item_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/line_item_list">

  <TextView
    android:layout_width="171dp"
    android:layout_height="wrap_content"
    android:text="LineItem List"
    android:id="@+id/line_item_list_text" />

  <com.linearlistview.LinearListView
    android:id="@+id/line_item_wrapper"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:divider="#f00"
    android:orientation="vertical"
    android:showDividers="middle"
    app:dividerThickness="16dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/tools"/>
</LinearLayout>

line_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/line_item">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="my line item."
    android:id="@+id/line_item_text"
    android:layout_gravity="center_horizontal" />

  <!-- notes child items go here -->

</LinearLayout>

LineItemFragment.java 使用适配器加载片段(此代码中的 lineItem 显示为上图中的单词 "Part"。)

public class LineItemFragment extends Fragment {
  LineItemAdapter adapter;

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


    LinearListView lineItems = (LinearListView)container.findViewById(R.id.line_item_wrapper);
    adapter = new LineItemAdapter(this.getContext(), getChildFragmentManager());
    lineItems.setAdapter(adapter);

    return null;

  }
}

LineItemAdapter.java

public class LineItemAdapter extends BaseAdapter{

  ArrayList<String> lineItems = new ArrayList<String>();
  Context context;
  FragmentManager fm;


  public LineItemAdapter(Context context, FragmentManager fragmentManager) {
    this.context = context;
    lineItems.add("Item A");
    lineItems.add("Item B");
    lineItems.add("Item C");
    this.fm = fragmentManager;
  }

  @Override
  public int getCount() {
    return lineItems.size();
  }

  @Override
  public Object getItem(int position) {
    return lineItems.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = ((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
                .inflate(R.layout.line_item, parent, false);
    }
        ((TextView)convertView.findViewById(R.id.line_item_text)).setText(getItem(position).toString());


    // *** The getView method could load the child fragments
    return convertView;
  }
}

在之前的文件 (***) 中,我目前认为 getView 方法应该加载下一级子片段,但我尝试过的所有方法都没有奏效。看来布局还没有膨胀,所以我不能给它添加子视图。

我的问题是,"how do i add child fragments from within the getView?" 或者我可能做错了。

这是我尝试过的一个例子:

lineItemAdapter.java 中的 getView 方法 (***):

.
.
.

    LinearLayout notes = (LinearLayout) ((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
            .inflate(R.layout.line_item, parent, false);

    LinearLayout b = (LinearLayout)((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
            .inflate(R.layout.note_list, notes).getRootView();

    NoteListFragment noteListFragment = new NoteListFragment();
    fm.beginTransaction().add(b.getId(), noteListFragment).commit();
.
.
.

我遇到了这样的异常。

E/AndroidRuntime: FATAL EXCEPTION: main

Process: com.example.myapplication, PID: 12207

java.lang.RuntimeException: Unable to start activity   
ComponentInfo{com.example.myapplication/com.example.myapplication.DetailActivity}: java.lang.IllegalStateException: Fragment does not have a view
                                                                            at 
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                            at   
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
.
.
.

提前致谢。

编辑

我是否需要在 xml 中添加片段,即:

line_item.xml...新节点:

<fragment android:name="com.example.noteListFragment"
          android:id="@+id/note_list_fragment"
          android:layout_weight="1"
          android:layout_width="0dp"
          android:layout_height="wrap_content" />

最后,我为此放弃了片段,并删除了 inflation 代码。相反,我加载了包含在 xml 中的相同布局结构,因此我不必构建比我已有的更大的 xml 文件。

对于我本应放入片段中的功能,我放入了演示器 类,然后使用 ButterKnife 的视图注入将演示器绑定到视图中的适当级别。

我仍在努力使用事件总线在层之间进行通信,就像@mt0s 建议的那样。

如果您想朝这个方向发展,这里有一些代码可以帮助您:

使用 include 我可以将整个结构放在一起,将每一层布局保存在自己的 xml 文件中:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_workorder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
    <LinearLayout
        android:id="@+id/workorder_detail_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <include layout="@layout/workorder_header"/> <!-- include other layouts -->
        <include layout="@layout/workorder_service_items"/>
    </LinearLayout>
</LinearLayout>

接下来我创建了一个 Presenter.class 文件来设置适配器,使用 ButterKnife 绑定到视图的那部分:

public class WorkOrderPresenter implements PropertyChangeListener
{

    private View detailView;
    private WorkOrder workOrder; // the object to display
    private List<WorkorderAsset> assetList;

    // Set your bindings to the view, passing the id from the layout.
    @Bind(R.id.workorderasset_list) View serviceItemDetail;
    @Bind(R.id.workorderasset_list_content) LinearListView assets;
    @Bind(R.id.number_of_service_items) TextView numberOfServiceItems;
    @Bind(R.id.total_value) TextView totalView;

    WorkOrderAssetAdapter workOrderAssetAdapter; // an adapter for a child list

    // Constructor
    public WorkOrderPresenter(View view, WorkOrder wo, final Activity activity)
    {
        workOrder = wo;
        detailView = view;
        ButterKnife.bind(this, detailView); //this is where the binding actually happens

        workOrderAssetContent = Provider.GetItems // Load you items for the adapter.

        // My system gives items back asynchronously:
        workOrderAssetContent.getWorkOrderAssets(workOrder.getWorkOrderID(), new iProvideCallback<List<WorkorderAsset>>() {
            @Override
            public void onSuccess(iResponse<List<WorkorderAsset>> response) {
                assetList = response.getResponse();
                numberOfServiceItems.setText(String.valueOf(assetList.size()));
                workOrderAssetAdapter = new WorkOrderAssetAdapter(activity, assetList); // construct the adapter with items.
                assets.setAdapter(workOrderAssetAdapter);
            }

            @Override
            public void onFailure(iResponse<List<WorkorderAsset>> response) {
                Toast.makeText(activity.getApplicationContext(), R.string.ServiceItemsError, Toast.LENGTH_LONG);

            }
        });
    }
}

这是一个显示项目的适配器:

public class WorkOrderAssetAdapter extends BaseAdapter
{
    private Activity activity;
    private List<WorkorderAsset> workorderAssetList;
    private static LayoutInflater inflater = null;

    // Constructor
    public WorkOrderAssetAdapter(Activity a, List<WorkorderAsset> items)
    {
        workorderAssetList = items;
        activity = a;
        inflater = LayoutInflater.from(activity);
    }

    @Override
    public int getCount() { return workorderAssetList.size(); }

    @Override
    public Object getItem(int position) { return workorderAssetList.get(position); }

    @Override
    public long getItemId(int position) { return position; }

    // view holder for the item
    public static class ViewHolder extends WorkOrderAssetViewHolder
    {
        @Bind(R.id.line_item_text) TextView line_item_text;
        @Bind(R.id.line_item_list) LinearListView list;

        // Adapter, Data Provider and Presenter for the next level.
        public WorkOrderAssetLineItemAdapter adapter;
        public WorkOrderAssetLineItemProvider provider;
        public WorkOrderAssetLineItemPresenter presenter;

        private Activity activity;
        private WorkorderAsset workOrderAsset;

        public VehicleViewHolder(WorkorderAsset asset, final View view, Activity activity_in)
        {
            ButterKnife.bind(this, view);
            workOrderAsset = asset;
            activity = activity_in;
            workOrderAssetLineItemContent = new WorkOrderAssetLineItemContent(((RoadFS)activity.getApplication()).getServer(), ((RoadFS)activity.getApplication()).getApplicationContext());
            workOrderAssetLineItemContent.getWorkOrderAssetLineItems(
                    workOrderAsset.getWorkOrderID(),
                    workOrderAsset.getWorkOrderAssetID(),
                    new iProvideCallback<List<WorkorderAssetLineItem>>() {

                        @Override
                        public void onSuccess(iResponse response) {
                            list.setAdapter(new WorkOrderAssetLineItemAdapter(activity,
                                    (List<WorkorderAssetLineItem>) response.getResponse(),
                                    view));
                        }

                        @Override
                        public void onFailure(iResponse response) {

                        }
                    });

        }

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

        WorkorderAsset workOrderAsset;
        workOrderAsset = workorderAssetList.get(position);
        ViewHolder holder;
        if (view != null) {
            holder = (ViewHolder) view.getTag();
        } else {
            view = inflater.inflate(R.layout.workorder_detail_workorderasset_vehicle, parent, false);
            holder = new VehicleViewHolder(workOrderAsset, view, activity);
            view.setTag(holder);
        }

        holder.item_text.setText(workOrderAsset.getVIN());

        holder.workOrderAssetLineItemContent = new WorkOrderAssetLineItemContent(((RoadFS) activity.getApplication()).getServer(), activity);
        holder.workOrderAssetLineItemAdapter = new WorkOrderAssetLineItemAdapter(activity, WorkOrderAssetLineItemContent.workorderAssetLineItemList, view);

        return view;
    }
}

这个例子有点不完整,我还没有一个示例项目,但希望它能帮助别人。它没有按预期回答问题,但是两种方式都尝试过,我认为这是一个更好的解决方案,因为它比处理片段的复杂性更简单。 Fragments 仍将用于更改屏幕 size/orientation,但 Fragments 将不会用于复杂布局。感谢您的任何输入。

  1. 对适配器

    使用不同的 class
    public class TabCategory extends Fragment {
        private ListView listView;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,   Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View tabCat=inflater.inflate(R.layout.tab_all, container, false);
            listView = (ListView) tabCat.findViewById(R.id.listView);
            //ADAPTER
            CategoryList adapter = new CategoryList(getContext());
            listView.setAdapter(adapter);
            return tabCat;
        }
    }