Android Action Bar Tab 在滚动视图中,方向变化后会产生重复的视图

11

我有一段非常简单的代码,其中使用了带有选项卡片段的操作栏。它在加载后很好用,但在方向改变后就会出现问题。为什么旧的片段仍然可见呢?

对于图片上的匈牙利文,我很抱歉,但我希望这不重要。 方向改变后

我附上了代码,也许它可以帮助解决这个问题。

主活动:

public class Main extends Activity
{
    private static ActionBar actionBar;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // setup action bar for tabs
        actionBar = getActionBar();
        actionBar.removeAllTabs();
        if (actionBar.getTabCount() == 0)
        {
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            Tab tab = actionBar.newTab().setText(R.string.starter).setTabListener(new TabListener<Starter>(this, "starter", Starter.class));
            actionBar.addTab(tab);

            tab = actionBar.newTab().setText(R.string.newword).setTabListener(new TabListener<NewWord>(this, "newwod", NewWord.class));
            actionBar.addTab(tab);

            tab = actionBar.newTab().setText(R.string.feedback).setTabListener(new TabListener<Feedback>(this, "feedback", Feedback.class));
            actionBar.addTab(tab);
        }

        if (savedInstanceState != null)
        {
            actionBar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    }
}

TabListener(与Google示例相同):

public class TabListener<T extends Fragment> implements android.app.ActionBar.TabListener
{
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    /**
     * Constructor used each time a new tab is created.
     * 
     * @param activity
     *            The host Activity, used to instantiate the fragment
     * @param tag
     *            The identifier tag for the fragment
     * @param clz
     *            The fragment's Class, used to instantiate the fragment
     */
    public TabListener(Activity activity, String tag, Class<T> clz)
    {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft)
    {
        // User selected the already selected tab. Usually do nothing.

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft)
    {
        // Check if the fragment is already initialized
        if (mFragment == null)
        {
            // If not, instantiate and add it to the activity
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else
        {
            // If it exists, simply attach it in order to show it
            ft.attach(mFragment);
        }

    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft)
    {
        if (mFragment != null)
        {
            // Detach the fragment, because another one is being attached
            ft.detach(mFragment);
        }
    }

}

片段:

public class Starter extends Fragment
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        setRetainInstance(false);
        return inflater.inflate(R.layout.newword, container, false);
    }
}

布局XML:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp" >

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="@string/newword"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <EditText
            android:id="@+id/newwordtext"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="@string/wordhint" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="@string/description"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/descriptionwordtext"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="@string/descriptionhint"
            android:inputType="textMultiLine"
            android:minLines="4" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="@string/origin"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/origintext"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="@string/originhint" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="@string/source"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/sourcetext"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:hint="@string/sourcehint" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="@string/name"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/nametext"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:inputType="textPersonName" />

        <Button
            android:id="@+id/sendbutton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:text="@string/send" />
    </LinearLayout>

</ScrollView>

Thank You in Advance!

5个回答

5

我在其他的问题中找到了一个可用的答案。

我需要修改我的TabListener(我将其移动到我的主活动类作为内部类):

private class TabListener<T extends Fragment> implements android.app.ActionBar.TabListener
    {
        private Fragment mFragment;
        private final Activity mActivity;
        private final String mTag;
        private final Class<T> mClass;

        /**
         * Constructor used each time a new tab is created.
         * 
         * @param activity
         *            The host Activity, used to instantiate the fragment
         * @param tag
         *            The identifier tag for the fragment
         * @param clz
         *            The fragment's Class, used to instantiate the fragment
         */
        public TabListener(final Activity activity, final String tag, final Class<T> clz)
        {
            mActivity = activity;
            mTag = tag;
            mClass = clz;
        }

        @Override
        public void onTabReselected(final Tab tab, final FragmentTransaction ft)
        {
            // User selected the already selected tab. Usually do nothing.
        }

        @Override
        public void onTabSelected(final Tab tab, final FragmentTransaction ft)
        {
            mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
            if (mFragment == null)
            {
                mFragment = Fragment.instantiate(mActivity, mClass.getName());
                ft.add(android.R.id.content, mFragment, mTag);
            }
            else
            {
                ft.attach(mFragment);
            }
        }

        @Override
        public void onTabUnselected(final Tab tab, final FragmentTransaction ft)
        {
            if (mFragment != null)
            {
                ft.detach(mFragment);
            }
        }
    }

所以,在我再次添加片段之前,我会检查它是否存在(并获取其引用),如果存在,则仅附加它。

1
我唯一要补充的是,在onTabUnselected方法中,在mFragment!= null检查之前,也应该添加这行代码“mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);”。否则,一切都很好! - SBerg413
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag); 这行代码也解决了我的问题,类不需要是内部的和私有的。 - Goldorak84

2
尝试在onTabSelected函数中使用ft.replace(R.id.content, mFragment)代替ft.attach(mFragment);

我尝试了这个:ft.replace(android.R.id.content, mFragment); 但它没有帮助(仍然有同样的问题),并且在再次选择选项卡后,它会删除选项卡的全部内容。 - sianis
呵呵...这段代码对我非常有效:if (fragmentManager.findFragmentById(R.id.frame_for_fragment) == null) { FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragment = new SomeFragment(); fragmentTransaction.add(R.id.frame_for_fragment, fragment); fragmentTransaction.commit(); } - Orest

1
我找到了一个非常简单的解决方案来避免片段重复:
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        Fragment currentFragment = getFragmentManager().findFragmentByTag(CURRENT_FRAGMENT_TAG);
        if (currentFragment == null || !currentFragment.getClass().equals(mFragment.getClass())) {
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.add(android.R.id.content, mFragment, CURRENT_FRAGMENT_TAG);
        }
    }

    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
        ft.remove(mFragment);
    }

解决方案的关键在于条件:

currentFragment == null || !currentFragment.getClass().equals(mFragment.getClass())

这个条件仅在片段的类不同的情况下有效。如果您有相同类的不同实例,则必须在片段中添加额外的属性以识别其功能(或与之关联),并使条件!currentFragment.getClass().equals(mFragment.getClass())为真:例如,您可以使用FragmentTransaction标签功能。

再见, Alex。


0
public void onTabSelected(Tab tab, FragmentTransaction ft)
    {
        // Check if the fragment is already initialized
        if (mFragment == null)
        {
            if(ft.findFragmentById(android.R.id.content) == null){
            // If not, instantiate and add it to the activity
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
            }
        } else
        {
            // If it exists, simply attach it in order to show it
            ft.attach(mFragment);
        }

    }

大概是这样,因为你的问题是添加了相同的片段两次,我们只需要找到在哪里...


0

我通过在选项卡监听器构造函数中查找片段来解决了这个问题。

public class TabListener<T extends Fragment> implements ActionBar.TabListener 
{
    private Fragment fragment;
    private final SherlockFragmentActivity activity;
    private final String tag;
    private final Class<T> clazz;

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clazz) 
    {
        this.activity = activity;
        this.tag = tag;
        this.clazz = clazz;

        FragmentManager manager = ((SherlockFragmentActivity) activity).getSupportFragmentManager();
        fragment = manager.findFragmentByTag(tag);
    }
...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接