横竖屏切换,activity结合fragment的导航布局

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a13570320979/article/details/52816956

先上效果图:

实现的效果是:竖屏下,收起左侧导航栏,显示右侧的内容栏,可通过滑动显示左侧的导航栏;横屏下,显示左侧的导航栏和右侧的内容栏,不能通过滑动隐藏导航栏。

首先,我们通过简单的几个步骤实现这个效果:

步骤一:创建布局文件,这里横竖屏使用的是不同的布局文件。在res文件下创建文件夹“layout-land”和"layout-port",前者用于存放横屏下的布局文件,后者用于存放竖屏下的布局文件。在“layout-land”文件夹中创建布局文件:activity_navigation.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">

    <FrameLayout
        android:id="@+id/ly_menu"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <FrameLayout
        android:id="@+id/ly_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
这里使用固定的布局,左侧的FrameLayout用于显示导航栏,右侧的FrameLayout用于显示主界面.

在“layout-port”文件下创建布局文件:activity_navigation.xml(文件名和layout-land下的文件名一致),如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/ly_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:id="@+id/ly_menu"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"/>

</android.support.v4.widget.DrawerLayout>
竖屏下,这里使用了DrawerLayout实现滑动功能。这里需要注意的是:横竖屏布局下的frameLayout的id是一样的,如用于展示导航栏的FrameLayout的id都是ly_menu,这样做的目的是方便activity管理fragment。

步骤二:在activity中引用上述布局,NavigationActivity.java如下:

package com.clement.example.switchscreen;

import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.clement.example.switchscreen.content.ContentFragment;
import com.clement.example.switchscreen.menu.MenuFragment;

public class NavigationActivity extends AppCompatActivity {

    private MenuFragment menuFragment;
    private ContentFragment contentFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_navigation);
        //初始化工作,绑定Fragment
        initVariables(savedInstanceState) ;
    }

    /**绑定fragment
     * @param savedInstanceState
     */
    private void initVariables(Bundle savedInstanceState){
        //初始化
        if(savedInstanceState==null){
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            contentFragment = new ContentFragment();
            menuFragment = new MenuFragment();
            fragmentTransaction.add(R.id.ly_content, contentFragment,ContentFragment.class.getSimpleName());
            fragmentTransaction.add(R.id.ly_menu,menuFragment,MenuFragment.class.getSimpleName());
            fragmentTransaction.commit();
        }
        //屏幕旋转之后
        else{
            FragmentManager fragmentManager = getFragmentManager();
            contentFragment = (ContentFragment) fragmentManager.findFragmentByTag(ContentFragment.class.getSimpleName());
            menuFragment = (MenuFragment)fragmentManager.findFragmentByTag(MenuFragment.class.getSimpleName());
        }
    }
}
该activity只是简单地绑定fragment。当屏幕发生旋转后,NavigationActivity都会销毁重建,自动加载对应的布局文件,到这里就已经实现了上述效果。

但这样是不够的,试想一下,这里的activity是用于管理fragment的,UI视图都是由fragment处理的,当fragment的视图发生了修改,例如contentFragment上有个编辑框,并且已经输入了“ABC”,这时屏幕发生旋转,我们可以发现“ABC”不见了,所有fragment的UI都变回了最初的状态。

那么首先要解决的问题是:横竖屏切换时,保持fragment视图状态。先看ContentFragment.java:

package com.clement.example.switchscreen.content;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.clement.example.switchscreen.R;

public class ContentFragment extends Fragment {
    //保存fragment的view
    private View rootView ;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设备旋转时保存Fragment的交互状态(activity重建时,fragment不执行onCreate和onDestroy)
        setRetainInstance(true);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(rootView==null){
            rootView = inflater.inflate(R.layout.fragment_content, container, false);
        }
        return rootView;
    }
}

当横竖屏切换时,系统会销毁并重建fragment的UI视图,但不会销毁该fragment的实例,通过全局变量rootView保存视图,用于重建时恢复原视图状态;setRetainInstance(true)的作用是:发生横竖屏切换,activity重建时,fragment不执行onCreate和onDestroy(注意onCreateView还是会执行的),因此一些用于初始化fragment的操作可以放在onCreate中,避免横竖屏切换时再次执行。同理,在onCreateView中也可以通过判断rootView是否为空,执行一些初始化操作或横竖屏切换后的操作。

到这里,上述效果就完全实现了。

关于扩展:

一.右侧的内容栏不止一个fragment:

假如希望右侧的内容栏能分割为多个fragment,有两种方向:

1.使用fragment嵌套,将ContentFragment当作父fragment,再往里边添加子fragment;

2.平级关系,不想使用嵌套。比如,现在想把右侧的只有一个fragment的布局修改为,由上下两个fragment组成的布局。新建布局文件:content_layout.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">
    <FrameLayout
        android:id="@+id/ly_top"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_56"/>
    <FrameLayout
        android:id="@+id/ly_bottom"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
修改activity_navigation.xml(注意横竖屏布局都要修改),将

<FrameLayout
    android:id="@+id/ly_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
修改为:

<include layout="@layout/detail_layout"
    android:id ="@+id/detail_layout"/>

在activity中修改一下绑定的fragment的逻辑就可以了。这里之所以使用include,主要是受到竖屏环境下使用了DrawerLayout的限制。

二.activity和fragment间的通信

建议还是把activity当做中转站,fragment之间不直接通信。这样也方便把activity和fragment进行封装;需要注意的一个地方是,横竖屏切换时,activity是销毁重建的,即activity的实例每次横竖屏切换后都是新的。例如,activity和fragment通过接口A进行通信,接口A的实例是fragment的一个变量,这样就需要在fragment的onAttach方法中更新接口A的实例了。


查看源码


猜你喜欢

转载自blog.csdn.net/a13570320979/article/details/52816956