而无需使用支持库最佳实践中的Android 4.0,4.1嵌套片段(<4.2)(Best pr

2019-07-23 04:16发布

我正在写一个应用程序为4.0和4.1平板电脑,对此我不想使用支持库 (如果不需要),但4.x的API,因此只。

所以我的目标平台是很好的定义为:> = 4.0和<= 4.1

的应用程序有一个多窗格布局(两个片段,一个小在左边,在右边一个内容片段),并与翼片的动作杆。

与此类似:

操作栏上点击标签改变“外”片段,然后将该片段内是具有两个嵌套的片段(1小左边的列表片段,2.宽内容片段)的片段。

我现在想知道什么是更换片段,尤其是嵌套片段的最佳实践。 该ViewPager是支持库的一部分,因此对于这类没有本地4.x的选择。 出现在我的意义来“不赞成使用”。 - http://developer.android.com/reference/android/support/v4/view/ViewPager.html

然后我读为Android 4.2的发布说明,关于ChildFragmentManager ,这将是一个不错的选择,但我瞄准4.0和4.1,所以这也不能被使用。

ChildFragmentManager仅在4.2可用

  • http://developer.android.com/about/versions/android-4.2.html#NestedFragments
  • http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()

不幸的是,几乎是显示片段用法的最佳实践,而不支持库,即使是在整个Android开发人员指南任何很好的例子在那里; 特别是只字不提嵌套的片段。

所以我想知道:这是根本不可能写4.1应用程序使用嵌套的片段,而无需使用支持库和一切随之而来? (需要使用的,而不是片段FragmentActivity等?)或者什么是最好的做法?


我目前有在发展中的问题,也正是这样的说法:

  • http://developer.android.com/about/versions/android-4.2.html#NestedFragments

Android的支持库现在还支持嵌套的片段,这样你就可以实现在Android 1.6及更高的分片嵌套设计。

注意:可以不膨胀的布局成片段时布局包括<fragment> 。 当添加到片段动态嵌套片段仅支持。

因为我把定义XML,这显然会导致错误像嵌套片段:

Caused by: java.lang.IllegalArgumentException: Binary XML file line #15: Duplicate id 0x7f090009, tag frgCustomerList, or parent id 0x7f090008 with another fragment for de.xyz.is.android.fragment.CustomerListFragment_

此刻,我总结我自己:即使在4.1的时候我甚至不想要的目标2.x的平台,如截图所示嵌套的片段是没有可能的支持库。

(这实际上可能不止一个问题维基条目,但也许别人以前管理的话)。

更新:

有帮助的答案是: 片段片段内

Answer 1:

限制

另一个片段内,从而嵌套片段是不可能的XML不论哪个版本FragmentManager使用。

所以,你必须通过代码添加片段,这似乎是一个问题,但是从长远来看,让您的布局超柔。

所以筑巢,而无需使用getChildFragmentManger ? 背后的本质childFragmentManager是,它推迟装载,直到前一个片段的交易已经完成。 当然还有它只是自然地在4.2或支持库支持。

嵌套不ChildManager - 解决方案

解决方案,当然! 我一直在这样做了很长一段时间,(因为ViewPager宣布)。

见下文; 这是一个Fragment的是推迟装载,所以Fragment S能够在其内部被加载。

它很简单,该Handler是一个非常非常方便类,有效的处理程序等待空间,在主线程中的当前片段交易完成后提交执行(如碎片与他们的主线程上运行的UI干扰)。

// Remember this is an example, you will need to modify to work with your code
private final Handler handler = new Handler();
private Runnable runPager;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    return inflater.inflate(R.layout.frag_layout, container, false);
}

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);
    runPager = new Runnable() {

        @Override
        public void run()
        {
          getFragmentManager().beginTransaction().addFragment(R.id.frag_container, MyFragment.newInstance()).commit();
        }
    };
    handler.post(runPager);
}

/**
 * @see android.support.v4.app.Fragment#onPause()
 */
@Override
public void onPause()
{
    super.onPause();
    handler.removeCallbacks(runPager);
}

我不认为这是“最佳做法”,但我用这个黑客活动的应用程序和我还没有遇到任何问题与它。

我也用这个方法嵌入查看传呼机- https://gist.github.com/chrisjenx/3405429



Answer 2:

在预API 17要做到这一点,最好的办法是这样做的。 试图实现这种行为会造成问题。 但是这并不是说,它不能令人信服地使用当前的API 14.我所做的是以下伪造的:

1 -看片段之间的通信http://developer.android.com/training/basics/fragments/communicating.html

2 - 从现有的片段移动您的布局XML的FrameLayout的活动布局和给予的高度为0隐藏:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">
<FrameLayout android:id="@+id/content"
          android:layout_width="300dp"
          android:layout_height="match_parent" />


<FrameLayout android:id="@+id/lstResults"
             android:layout_width="300dp"
             android:layout_height="0dp"
             android:layout_below="@+id/content"
             tools:layout="@layout/treeview_list_content"/>


<FrameLayout android:id="@+id/anomalies_fragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
        android:layout_toRightOf="@+id/content" />

3 - 实施在父片段的界面

    OnListener mCallback;

// Container Activity must implement this interface
public interface OnListener 
{
    public void onDoSomethingToInitChildFrame(/*parameters*/);
    public void showResults();
    public void hideResults();
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // This makes sure that the container activity has implemented
    // the callback interface. If not, it throws an exception
    try {
        mCallback = (OnFilterAppliedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnListener");
    }
}

@Override
public void onActivityCreated(Bundle savedInstanceState) 
{
    super.onActivityCreated(savedInstanceState);

    mCallback.showResults();
}

@Override
public void onPause()
{
    super.onPause();

    mCallback.hideResults();
}

public void onClickButton(View view)
{
    // do click action here

    mCallback.onDoSomethingToInitChildFrame(/*parameters*/);
}

4 - 实施在父活动的界面

公共类YourActivity延伸活动实现yourParentFragment.OnListener {

public void onDoSomethingToInitChildFrame(/*parameters*/)
{
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment == null)
    {
        childFragment = new yourChildFragment(/*parameters*/);
        ft.add(R.id.lstResults, childFragment, "Results");
    }
    else
    {
        ft.detach(childFragment);

        ((yourChildFragment)childFragment).ResetContent(/*parameters*/);

        ft.attach(childFragment);
    }
    ft.commit();

    showResultsPane();
}

public void showResults()
{
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment != null)
        ft.attach(childFragment);
    ft.commit();

    showResultsPane();
}

public void showResultsPane()
{
    //resize the elements to show the results pane
    findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
    findViewById(R.id.lstResults).getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
}

public void hideResults()
{
    //resize the elements to hide the results pane
    findViewById(R.id.content).getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    findViewById(R.id.lstResults).getLayoutParams().height = 0;

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment childFragment = getFragmentManager().findFragmentByTag("Results");
    if(childFragment != null)
        ft.detach(childFragment);
    ft.commit();
}

}

5 - 享受,用这种方法你会得到相同的流体功能与A-API前17 envoronment的getChildFragmentManager()函数。 正如你可能已经注意到孩子片段不再真正的父片段的孩子,但现在活动的孩子,这真的是无法避免的。



Answer 3:

我不得不处理这个确切的问题,由于NavigationDrawer,TabHost和ViewPager的组合,有并发症的,因为TabHost支持库的使用。 然后我也有支持的豆形软糖4.1分钟API,所以使用嵌套的片段,片段getChildFragmentManager不是一种选择。

所以,我的问题可以蒸馏...

  TabHost(对于顶层)  + ViewPager(为顶级标签片段的只是一个)  =需要嵌套片段(其杰利贝恩4.1将不支持) 

我的解决办法,而无需实际嵌套片段创建嵌套片段的错觉。 我由具有主活动中使用TabHost和ViewPager管理两个兄弟查看其可见性是由0和1之间切换layout_weight管理这样做。

//Hide the fragment used by TabHost by setting height and weight to 0
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0);
mTabHostedView.setLayoutParams(lp);
//Show the fragment used by ViewPager by setting height to 0 but weight to 1
lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 1);
mPagedView.setLayoutParams(lp);

这有效地让我的假“分片嵌套”作为一个独立的观点,只要我手动管理的相关布局权重操作。

这里是我的activity_main.xml中:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ringofblades.stackoverflow.app.MainActivity">

    <TabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <FrameLayout android:id="@android:id/tabcontent"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"/>
            <android.support.v4.view.ViewPager
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/pager"
                android:background="@drawable/background_image"
                android:layout_width="match_parent"
                android:layout_weight="0.5"
                android:layout_height="0dp"
                tools:context="com.ringofblades.stackoverflow.app.MainActivity">
                <FrameLayout
                    android:id="@+id/container"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </android.support.v4.view.ViewPager>
            <TabWidget android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </TabHost>

    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="com.ringofblades.stackoverflow.app.NavigationDrawerFragment"
        tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

请注意, “@ + ID /寻呼机” 和 “@ + ID /容器”,均与兄弟姐妹的机器人:layout_weight = “0.5”“和 '机器人:layout_height = ”0dp“'。 这是为了让我可以在预览任何屏幕尺寸看到它。 他们的权重将在代码在运行时被操纵,反正。



Answer 4:

在@ Chris.Jenkins答案的基础上,这是对我一直运作良好,去除在生命周期事件(这不得不放弃IllegalStateExceptions的倾向)片段(S)的解决方案。 本品采用处理器相结合的办法,和Activity.isFinishing()检查(否则会抛出一个错误“无法后的onSaveInstanceState执行此操作)。

import android.app.Activity;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;

public abstract class BaseFragment extends Fragment {
    private final Handler handler = new Handler();

    /**
     * Removes the {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to
     * compensate for illegal states.
     *
     * @param fragment The {@link Fragment} to schedule for removal.
     */
    protected void removeFragment(@Nullable final Fragment fragment) {
        if (fragment == null) return;

        final Activity activity = getActivity();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (activity != null && !activity.isFinishing()) {
                    getFragmentManager().beginTransaction()
                            .remove(fragment)
                            .commitAllowingStateLoss();
                }
            }
        });
    }

    /**
     * Removes each {@link Fragment} using {@link #getFragmentManager()}, wrapped in a {@link Handler} to
     * compensate for illegal states.
     *
     * @param fragments The {@link Fragment}s to schedule for removal.
     */
    protected void removeFragments(final Fragment... fragments) {
        final FragmentManager fragmentManager = getFragmentManager();
        final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragmentTransaction.remove(fragment);
            }
        }

        final Activity activity = getActivity();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (activity != null && !activity.isFinishing()) {
                    fragmentTransaction.commitAllowingStateLoss();
                }
            }
        });
    }
}

用法:

class MyFragment extends Fragment {
    @Override
    public void onDestroyView() {
        removeFragments(mFragment1, mFragment2, mFragment3);
        super.onDestroyView();
    }
}


Answer 5:

虽然OP可能有阻止他使用的支持库特殊情况下,大多数人都应该使用它。 Android的文档建议它,它会让你的应用程序提供给更多观众。

在我丰满的答案在这里我做了一个例子,演示如何使用嵌套的片段与支持库。



文章来源: Best practice for nested fragments in Android 4.0, 4.1 (<4.2) without using the support library