选择其他选项卡后,如何更改内容视图? (Android HoneyCombGallery示例相关)

时间:2011-12-15 12:38:13

标签: android android-layout

我正在尝试修改HoneyCombGallery示例代码,以便在更改选项卡时更改显示的视图。在Google提供的示例中,切换标签时显示的片段始终相同。仅显示的数据发生变化。但是,我想要做的是更改标签更改时显示的片段和类。

以下是我在HoneyCombGallery示例中修改过的代码:(MainActivity.java)

public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
    int nTabSelected = tab.getPosition();
    switch (nTabSelected) {
    case 0:
        setContentView(R.layout.settings_fragment);
        break;
    case 1:
        setContentView(R.layout.main);
        break;
    }

其他一切都差不多。 (另请注意,如前所述,MainActivity.onCreate调用setContentView(R.layout.main) - 我没有听说过多次调用setContentView是不允许的。我打算在每个标签中单击这样做)

这是在代码中膨胀的布局(settings_fragment.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/frags2">
    <fragment class="com.example.android.hcgallery.SettingsFragment"
            android:id="@+id/settings_fragment2"
            android:visibility="gone"
            android:layout_marginTop="?android:attr/actionBarSize"
            android:layout_width="@dimen/titles_size"
            android:layout_height="match_parent" />
</LinearLayout>

“settings fragment”是我的类,它扩展了Fragment:(SettingsFragment.java)

public class SettingsFragment extends Fragment {
    private View v;
    @Override
    public View onCreateView(final LayoutInflater inflater,
            final ViewGroup container, final Bundle savedInstanceState) {

        if (v != null)
            return v;
        v = inflater.inflate(R.layout.settings_layout, container, false);
        return v;
    }
}

xml也非常简单(settings_layout.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/settings_layout" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingTop="10dip">

    <TextView android:text="1.0.0" android:id="@+id/tv_version2"
        android:layout_marginTop="?android:attr/actionBarSize"
        android:textSize="15dp" android:textStyle="bold" android:typeface="sans"
        android:layout_height="wrap_content" android:layout_width="200dp"
        android:paddingTop="10dip" android:gravity="right"  >
    </TextView>
</RelativeLayout>

这似乎很简单,当应用程序启动时,settings_fragment可见,因为默认选择了第0个选项卡。当我们选择下一个选项卡时,我希望执行setContentView(R.layout.main),我将看到主要布局(这与Google示例中的相同:无修改)。但是,我得到的是这个例外:

12-15 16:49:28.501: ERROR/AndroidRuntime(31485): FATAL EXCEPTION: main
12-15 16:49:28.501: ERROR/AndroidRuntime(31485): android.view.InflateException: Binary XML file line #23: Error inflating class fragment
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:688)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:724)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.inflate(LayoutInflater.java:391)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.inflate(LayoutInflater.java:347)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:224)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.app.Activity.setContentView(Activity.java:1777)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.example.android.hcgallery.MainActivity.onTabSelected(MainActivity.java:109)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.app.ActionBarImpl.selectTab(ActionBarImpl.java:462)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.app.ActionBarImpl$TabImpl.select(ActionBarImpl.java:787)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.widget.ActionBarView$TabClickListener.onClick(ActionBarView.java:950)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.View.performClick(View.java:3100)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.View$PerformClick.run(View.java:11644)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.os.Handler.handleCallback(Handler.java:587)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.os.Handler.dispatchMessage(Handler.java:92)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.os.Looper.loop(Looper.java:126)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.app.ActivityThread.main(ActivityThread.java:3997)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at java.lang.reflect.Method.invokeNative(Native Method)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at java.lang.reflect.Method.invoke(Method.java:491)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at dalvik.system.NativeStart.main(Native Method)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485): Caused by: java.lang.IllegalArgumentException: Binary XML file line #23: Duplicate id 0x7f09000a, tag null, or parent id 0x7f090009 with another fragment for com.example.android.hcgallery.TitlesFragment
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.app.Activity.onCreateView(Activity.java:4095)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664)
12-15 16:49:28.501: ERROR/AndroidRuntime(31485):     ... 21 more

错误似乎是“android.view.InflateException:二进制XML文件行#23:错误膨胀类片段”

这是什么意思?当选择不同的标签时,我可以不按照我的意愿更改片段和布局吗? 如果这不是为不同标签设置不同布局的正确方法,那么正确的方法是什么?

我已将整个源代码压缩上传到HoneycombGallery_Modified.zip - https://docs.google.com/open?id=0B0FHtQOpOYx6YWFiMDcxYmEtOGFkMy00NWU2LTk2MzMtZWY0YzdmZWUzMDU0(如果您要下载整个zip文件,请点击“文件 - &gt;下载原件”)

3 个答案:

答案 0 :(得分:3)

我成功地实现了你所需要的。

我的情况:我有一个带有多个标签的操作栏,这些标签需要不同的布局才能正常显示。 我也使用ActionBarSherlock来实现向后兼容,但我认为原始类可以使用相同的原则。

我有2种标签:

  • 选项卡显示带有片段的列表,以显示列表中所选项目的内容(这是典型的片段样本)
  • 用于显示简单webView的标签

这是我的方式,我有一个名为ActionBarActivity的类,它初始化选项卡并包含TabListener。

这是我的ActionBarActivity:

public class ActionBarActivity
        extends SherlockFragmentActivity
{
    /**
    * The current layoutId on the screen
    */
    private int layoutId;
    protected final int LAYOUT_LIST = R.layout.list_container;
    protected final int LAYOUT_WEBVIEW = R.layout.webview_container;

    @Override
    public void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );
        ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode( ActionBar.NAVIGATION_MODE_TABS );
        getSupportActionBar().removeAllTabs();
        // we pass the layout to use for each tab
        addTab("Tab 1", LAYOUT_LIST, ListFragment.class);
        addTab("Tab 2", LAYOUT_WEBVIEW, WebViewFragment.class);

        // in case of screen orientation
        if ( savedInstanceState != null ) {
            actionBar.setSelectedNavigationItem( savedInstanceState.getInt( "tab", 0 ) );
        }
        // initial setting of the content 
        updateContentView( actionBar.getSelectedTab() );

    }

    private void addTab( String title, int contentLayoutId, Class<? extends Fragment> tabClass )
    {
        Tab t = getSupportActionBar().newTab();
        t.setText( tabTitle );
        t.setTag( contentLayoutId );
        t.setTabListener( new TabListener( this, tabTitle, activity, null ) );
        getSupportActionBar().addTab( t );
    }

    // that's how I deal to replace the layout used to display the tab's content 
    protected void updateContentView( Tab t )
    {
        FragmentManager fgtManager = getSupportFragmentManager();
        int tabLayoutId = ( Integer ) t.getTag();

        if ( tabLayoutId == LAYOUT_WEBVIEW ) {

            Fragment details = fgtManager.findFragmentById( R.id.detail_fragment);

            if(details != null && details.isInLayout()){
                FragmentTransaction transact = fgtManager.beginTransaction();
                transact.remove( details );
                transact.commit();
                details = null;
            }
        }

        if ( this.layoutId != tabLayoutId ) {
            layoutId = tabLayoutId;
            setContentView( layoutId );
        }
    }

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

    // see APIDemos.app.FragmentTabs for more details 
    public static class TabListener
            implements ActionBar.TabListener
    {
        private SherlockFragmentActivity mActivity;

        public void onTabSelected( Tab tab, FragmentTransaction ft )
        {
            // When we select a tab we udpate the content of the ActionBarActivity 
            ((ActionBarActivity)mActivity).updateContentView( tab );

            mFragment = mActivity.getSupportFragmentManager().findFragmentByTag( mTag );
            if ( mFragment == null ) {
                mFragment = Fragment.instantiate( mActivity, mClass.getName(), mArgs );
                ft.add( R.id.content_fragment, mFragment, mTag );
            } else {
                ft.attach( mFragment );
            }
        }
    }
}

我的两个布局:

布局/ list_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="horizontal">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="0.6"
        android:id="@+id/content_fragment"/>
    <fragment
        android:id="@+id/detail_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="0.4"
        class="my.webview.WebViewFragment">
    </fragment>
</LinearLayout>

布局/ webview_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
        <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:id="@+id/content_fragment"/>
</LinearLayout>    
PS:这是我的第一个贡献,所以我很高兴有一些批评者。

PPS:我是法国人,所以我可能忘记了一些英语错误,对不起。

答案 1 :(得分:1)

答案 2 :(得分:0)

我认为你不应该再次设置内容,它只能设置一次。 使用fragmentTransaction.replace()

将适当的片段设置到片段容器中