Android Studio —— Fragment

144 阅读3分钟

第一行代码读书笔记

碎片

  • 碎片是一种考验嵌入活动中的UI片段
  • 在平板上广泛应用

基础使用

  • 新建两个碎片

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Button"
            />
    
    </LinearLayout>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:background="#00ff00"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="20sp"
            android:text="This is a right fragment"
            />
    </LinearLayout>
    
  • 新建LeftFragmetn类,继承自Fragment

    public class LeftFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.left_fragment, container, false);
            return view;
        }
    }
    
    • support-v4库中的Fragment支持版本兼容 android.support.v4.app.Fragment
    • 重写onCreateView()方法,通过LayoutInflater的inflate()方法将left_fragment布局动态加载进来
  • 同理新建RightFragment类

public class RightFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.right_fragment, container, false);
        return view;
    }
}
  • 修改activity_main.xml
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:id="@+id/lft_fragment"
            android:name="com.example.fragmenttest.LeftFragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
        <fragment
            android:id="@+id/right_fragment"
            android:name="com.example.fragmenttest.RightFragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
    </LinearLayout>
    
    • 使用<fragment>标签
    • android:name
      • 显式指明要添加的碎片类名
      • 类的包名也要加上

动态添加碎片

  • 新建another_right_fragment.xml
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:background="#ffff00"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="20sp"
            android:text="This is another right fragment"
            />
    
    </LinearLayout>
    
  • 新建AnotherRightFragment类
    public class AnotherRightFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.another_right_fragment, container, false);
            return view;
        }
    }
    
  • 修改activity_main.xml,将right_fragment替换为
    <FrameLayout
        android:id="@+id/right_layout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />
    
  • 修改MainActivity,向FrameLayout添加内容
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(this);
            replaceFragment(new RightFragment());
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    replaceFragment(new AnotherRightFragment());
                    break;
                default:
                    break;
            }
        }
    
        private void replaceFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            transaction.replace(R.id.right_layout, fragment);
            transaction.commit();
        }
    }
    
  • 动态添加碎片主要分为5步
    1. 创建待添加的碎片实例
    2. 获取FragmentManager,在活动中可以直接通过调用getSupportFragmentManager()的方式得到
    3. 开启一个事务FragmentTransaction,通过调用beginTransaction()方法开启
    4. 向容器内添加或替换碎片,一般使用replace()方法实现,需要传入容器的id和待添加的碎片实例
    5. 提交事务,调用commit()方法完成

在碎片中模拟返回栈

  • FragmentTransaction中提供了addToBackStack()方法
    private void replaceFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.right_layout, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }
    
    • 用于将事务添加到返回栈中
    • 接收一个名字用于描述返回栈的状态
      一般传入null

碎片和活动之间通信

  • FragmentTransaction中提供了findFragmentById()方法
    RightFragment rightFragment = (RightFragment) getFragmentManager()
        .findFragmentById(R.id.right_fragment);
    
    • 用于从布局文件中获取碎片的实例
  • getActivity()
    MainActivity activity = (MainActivity) getActivity();
    
    • 用于获取和当前碎片相关联的活动实例
    • 当碎片中需要使用Context对象时也可以使用
      获取到的活动本身就是Context对象

碎片的生命周期

碎片的状态和回调

  1. 运行状态
    • 可见的,并且它所关联的活动正处于运行状态
  2. 暂停状态
    • 当一个活动进入暂停状态,与它关联的可见碎片就会进入暂停状态
  3. 停止状态
    • 当一个活动进入停止状态,与它关联的碎片就会进入停止状态
    • 通过调用FragmentTransaction的remove()replace()方法将碎片从活动中移除,
      但在事务提交前调用addToBackStack()方法,该碎片进入停止状态
    • 完全不可见的,有可能被系统回收
  4. 销毁状态
    • 当活动被销毁时,与它关联的碎片就会进入销毁状态
    • 通过调用FragmentTransaction的remove()replace()方法将碎片从活动中移除,
      但在事务提交前没有调用addToBackStack()方法,该碎片进入销毁状态
  • onAttach():当碎片和活动建立关联时调用
    onCreateView():为碎片创建视图(加载布局)时调用
    onActivityCreated():确保与碎片关联的活动一定已经创建完毕时调用
    onDestroyView():当与碎片关联的视图被移除时调用
    onDetacch():当碎片和活动解除关联时调用
  • 碎片的完整生命周期
    -> onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume() -> 碎片激活
    (移除)
    -> onPause() -> onStop() -> onDestroyView()(如果是返回栈中的碎片,回到上一个碎片onCreateView())-> onDestroy() -> onDetach()

动态加载布局的技巧

限定符

  • Quilifier
  • 在res目录下新建layout-large文件夹
    屏幕被认为是large的设备就会自动加载layout-large文件夹下的布局
  • 大小
    • small, normal, large, xlarge
  • 分辨率
    • ldpi, mdpi, hdpi, xhdpi, xxhdpi
  • 方向
    • land(横屏), port(竖屏)

最小宽度限定符

  • Smallest-width Qualifier
  • dp为单位
  • E.g. 新建文件夹layout-sw600d