fengyeezju 2019-12-19
本系列文章目录:更多精品文章分类
本系列持续更新中.... 初级阶段内容参考《第一行代码》
平板电脑和手机最大的区别就在于屏幕的大小,一般手机的屏幕大小会在 3 英寸到 6 英寸之间,而一般平板电脑屏幕大小会在 7 英寸到 10 英寸之间。屏幕大小差距过大会导致同样的界面视觉效果有很大的差异。
为了兼顾手机和平板开发,Android 3.0 引入了碎片的概念,可以让界面在平板上更好的展示。
碎片(Fragment)是一种可以嵌入到 Activity 中的 UI 片段,让程序更加合理和充分利用屏幕的空间。它和 Activity 很像,同样都能包含布局,同样有生命周期。
如何利用平板的屏幕空间呢?比如我们要开发一个新闻类的 APP。在手机端可以是这样的。
可以是如果在平板上也这样设计,那么新闻标题列表就会给拉伸的很长,而新闻的标题一般都不会太长,这样设计就会导致页面不合理。
因此,更好的设计方案是将新闻列表和新闻详细内容界面放到两个碎片中,然后在同一 Activity 中引入这两个碎片,这样屏幕空间就充分利用起来了。
首先我们先创建一个平板的模拟器,准备好后新建一个包用于碎片化的练习。
写一个最简单的碎片示例,在一个 Activity 中添加两个碎片,并让这两个碎片平方 Activity 空间。
left_fragment.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"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" android:layout_gravity="center_horizontal" android:id="@+id/bt"/> </LinearLayout>
right_fragment.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:background="#FF0000" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="20sp" android:text="This is right Fragment"/> </LinearLayout>
public class LeftFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.left_fragment, container, false); return view; } }
RightFragment
public class RightFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.left_fragment, container, false); return view; } }
fragmentbaseuse_activity
代码<?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"> <fragment android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:name="com.example.firstcode.fourth_chapter.LeftFragment" android:id="@+id/fg_left"/> <fragment android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:name="com.example.firstcode.fourth_chapter.RightFragment" android:id="@+id/fg_right"/> </LinearLayout>
这里使用了 <fragment>
标签在布局中添加碎片,然后在标签中通过 android:name
属性来指明要添加的碎片的类名,注意一定要把包名加上。
运行结果:
在上一节中我们学习了如何在布局中添加碎片,下面我们来学习如何用代码动态的添加碎片。
新建一个 another_right_fragment
<?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:background="#FFFF00" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="20sp" android:text="another fragment"/> </LinearLayout>
里面代码基本相同,只是更该了一下背景颜色,用来区分。
再新建一个 Fragement
public class AnotherRightFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.another_right_fragment, container, false); return view; } }
修改主页面的布局
<?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"> <fragment android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:name="com.example.firstcode.fourth_chapter.LeftFragment" android:id="@+id/fg_left"/> <!-- <fragment android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:name="com.example.firstcode.fourth_chapter.RightFragment" android:id="@+id/fg_right"/>--> <FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:id="@+id/framelayout"/> </LinearLayout>
将 <fragment>
替换成了 FrameLayout
,FragmentLayout 是 Android 中最简单的一种布局,所有的控件默认会摆放在布局的左上角。这里仅需要放入一个碎片,不需要任何定位,因此非常适合使用 FrameLayout
下面在代码中向 FrameLayout
中添加内容,从而实现动态添加碎片的功能。
public class FragmentBaseActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragmentbase); Button button = findViewById(R.id.bt); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { replaceFragment(new AnotherRightFragment()); } }); replaceFragment(new RightFragment()); } private void replaceFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.framelayout,fragment); fragmentTransaction.commit(); } }
首先给左侧碎片中的按钮注册了点击事件,然后调用了 replaceFragment()
方法动态的添加了 RightFragment
这个碎片。当点击左侧按钮的时候,就会触发 replaceFragment()
这个方法。
动态添加碎片主要分为 5 步:
FrgmentManager
,FragmentManager
是一个抽象类,在 Activity 中通过 getSupportFragmentManager()
方法来获取。beginTransaction()
方法开启replace()
就可以了。commit()
方法来完成。这样就完成了。
在上一小节中已经学习了如何动态添加碎片,不过当我们按下 Back
键程序就直接退出了,如何实现类似于返回栈的效果,当按下 Back
键的时候返回到上一个碎片呢?
FragmentTransaction
中提供了一个 addToBackStack()
方法,可以用于将一个事务添加到返回栈中。
private void replaceFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.framelayout,fragment); // 可以接受一个名字用于描述返回栈的状态,一般传入 null 即可 会将这个 Fragment 添加到栈中 fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); }
这样再运行程序,你会发现按下 Back
后程序没有立马退出,而是先退出了 Fragment
,等 Fragment
界面也消失了,再按下 Back
才会退出。
为了方便碎片和活动之间进行通信,FragmentManager 提供了一个类似于 findViewById()
的方法,专门用于从布局文件中获取碎片的实例。
RightFragment rightFragment = (RightFragment)getSupportFragmentManager().findFragmentById(R.id.right_fragment)
这个方法是适用于在布局中通过<fragment>
静态添加 Fragment
的情况,如果是动态的,就直接 new Fragment() 了。
那么如何在碎片中调用 Activity 呢?其实每个碎片中都可以通过调用 getActivity()
方法来得到和当前碎片相关联的 Activity 实例。
那么碎片与碎片直接如何通信呢?
思路:首先在一个碎片中可以得到与之关联的 Activity,然后通过这个 Activity 再去获取另外一个碎片实例就可以了。