【问题标题】:Restore views in a fragment added programmatically恢复以编程方式添加的片段中的视图
【发布时间】:2014-09-24 13:54:33
【问题描述】:

我有一个带有导航抽屉的活动(Eclipse 新应用程序向导提供的基本活动)。我有一个 FrameLayout 作为应用程序不同片段的容器,在选择导航抽屉中的项目时会替换这些片段。它们也被添加到 BackStack 中。

这些片段包含一个 LinearLayout,它有一些 EditTexts 和一个 Button。如果按下按钮,则会创建一个新的 LinearLayout 并添加几个 TextViews 以及 EditTexts 的内容。用户可以多次重复此选项,因此我无法确定需要多少个 LinearLayout,因此我需要以编程方式添加它们。

其中一个片段 xml:

<LinearLayout
    android:id="@+id/pen_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/new_pen_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:background="@drawable/border"
        android:orientation="vertical"
        android:paddingBottom="@dimen/home_section_margin_bottom"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/home_section_margin_top" >

        <EditText
            android:id="@+id/new_pen_round"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:hint="@string/new_pen_round_hint"
            android:textSize="@dimen/normal_text_size" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:weightSum="2" >

            <Button
                android:id="@+id/new_pen_cancel_button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="@dimen/new_item_button_margin_right"
                android:layout_weight="1"
                android:background="@drawable/button_bg"
                android:paddingBottom="@dimen/new_item_button_padding_bottom"
                android:paddingTop="@dimen/new_item_button_padding_top"
                android:text="@string/new_item_cancel_button"
                android:textSize="@dimen/normal_text_size" />

            <Button
                android:id="@+id/new_pen_insert_button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/new_item_button_margin_left"
                android:layout_weight="1"
                android:background="@drawable/button_bg"
                android:paddingBottom="@dimen/new_item_button_padding_bottom"
                android:paddingTop="@dimen/new_item_button_padding_top"
                android:text="@string/new_pen_insert_button"
                android:textSize="@dimen/normal_text_size" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

实际上还有很多其他的 EditText,但我在这里删除了它们以保持简短,结果是一样的。这是java文件:

public class PenaltiesFragment extends Fragment {

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_penalties, container, false);
        Button insertNewPen = (Button) view.findViewById(R.id.new_pen_insert_button);
        insertNewPen.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {               
                TextView round = (TextView) getActivity().findViewById(R.id.new_pen_round);
                LinearLayout layout = (LinearLayout) getActivity().findViewById(R.id.pen_layout);
                int numChilds = layout.getChildCount();
                CustomPenaltyLayout penalty = new CustomPenaltyLayout(getActivity(), round.getText()); 
                layout.addView(penalty, numChilds - 1);
            }
        });

        return view;
    }
}

我删除了一些无用的方法,它们只是默认的。 CustomPenaltyLayout是我创建的 LinearLayout 的子类,它只是创建一些 TextView 并将它们添加到自身。

这里一切正常。用户在 EditText 中插入数据,按下 Insert 按钮,一个新的布局被创建并添加到片段中。

我想要实现的是:假设我打开导航抽屉并选择另一个页面,片段被替换,如果我回到这个片段(通过导航抽屉或后退按钮)我想要文本,即用户添加,仍然存在。

我不会在每次切换回此片段时调用PenaltiesFragment.newInstance(),而是创建一次PenaltiesFragment 对象并继续使用该对象。我就是这样做的:

Fragment fragment;
switch (newContent) {
// various cases
case PEN:
    if(penFragment == null) // penFragment is a private field of the Main Activity
        penFragment = PenaltiesFragment.newInstance();
    fragment = penFragment;
    break;
}
getSupportFragmentManager()
    .beginTransaction()
    .replace(R.id.container, fragment)
    .addToBackStack("fragment back")
    .commit();

我知道在重新加载片段时会再次调用onCreateView(),对吗?所以这可能就是我看到一个新的空白片段的原因。但是如何让插入的CustomPenaltyLayout 回来?我无法在onCreateView() 方法中创建它。

【问题讨论】:

  • 绝对需要继承 LinearLayout 吗?无论如何,如果您以编程方式添加一些视图,如果您不为每个添加的视图提供唯一的 ID,系统将不会保留它们的状态。这是一个相关的教程:android-er.blogspot.it/2012/06/…
  • 这不是必需的,但在我看来很有用,因为我必须添加许多并且我希望它们具有相同的边距、背景、填充,另外我可能需要添加一两个里面的按钮,它将布局内容发送到服务器和其他东西。好的,我会尝试添加一个 ID,但是如果我不知道需要多少个 ID 怎么办?
  • 那为什么不直接扩充一个普通的 XML 文件呢?关于多个id,请看这个问题的第二个答案:stackoverflow.com/questions/1714297/…。但是,我会先尝试使用固定数量的视图来检查问题是否真的解决了。
  • 是的,这就是我现在所做的。我使用 id &lt;item type="id" name="myid" /&gt; 创建了 ids.xml 文件,然后将我以编程方式添加的布局 id 设置为 setId(R.id.myid)。我添加了一个布局,我切换到另一个片段,然后按回,但我添加的布局不存在。我是否还需要为 LinearLayout 中的对象设置 id?我注意到 EditTexts 的内容正确地保留了下来。我的问题可能是 onDestroyView() 被调用了吗?
  • 我认为您需要为每个以编程方式添加的视图/布局设置一个ID。

标签: java android android-layout android-fragments


【解决方案1】:

我找到了解决问题的方法。我用 ViewPager 替换了 Android 自动创建的默认 FrameLayout 作为我的 Fragment 的容器,然后像这样创建了 FragmentPagerAdapter:

public static class MyAdapter extends FragmentPagerAdapter {

    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment;
        switch (position) {
        // ...other cases
        case PEN:
            fragment = PenaltiesFragment.newInstance();
            break;
        // ...other cases
        }
        return fragment;
    }

    @Override
    public int getCount() {
        return 6;
    }
}

那么,要始终保留所有视图,唯一要做的就是将此行添加到我的活动onCreate 方法中。

mPager.setOffscreenPageLimit(5);

请参阅documentation 了解有关此方法如何工作的详细信息。

尽管如此,我不得不重新实现所有的后退按钮逻辑,但它仍然很简单,我就是这样做的:我创建了一个 java.util.Stack&lt;Integer&gt; 对象,向它添加片段编号(除非你使用后退按钮,见下文),并覆盖 onBackPressed() 以使其弹出最后查看的片段,而不是使用后退堆栈,当我的历史堆栈不为空时。

当你按下后退按钮时,你要避免将元素压入堆栈,否则如果你继续使用后退按钮,你会卡在两个片段之间,而不是最终退出。

我的代码:

MyAdapter mAdapter;
ViewPager mPager;
Stack<Integer> pageHistory;
int currentPage;
boolean saveToHistory;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mAdapter = new MyAdapter(getSupportFragmentManager());
    mPager = (ViewPager)findViewById(R.id.container);
    mPager.setAdapter(mAdapter);
    mPager.setOffscreenPageLimit(5);

    pageHistory = new Stack<Integer>();
    mPager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int arg0) {
            if(saveToHistory)
                pageHistory.push(Integer.valueOf(currentPage));
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
    saveToHistory = true;
}

@Override
public void onBackPressed() {
    if(pageHistory.empty())
        super.onBackPressed();
    else {
        saveToHistory = false;
        mPager.setCurrentItem(pageHistory.pop().intValue());
        saveToHistory = true;
    }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多