碎片是一种可嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕空间,因而在平板上的应用得非常广泛。碎片和活动非常的像,同样都能包含布局,同样有自己的生命周期。
写两个碎片平分活动空间。
left_fragment.xml
<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>
right_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00">
<TextView
android:id="@+id/tetView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20dp"
android:text="This is right fragment."/>
LinearLayout>
然后新建两个类,对应着上面的两个布局,LeftFragment 和 RightFragment,并让它们继承自Fragment.
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;
}
}
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.right_fragment,container,false);
return view;
}
}
这里重写了onCreateView()方法,然后在这个方法中通过LayoutInflater的inflate()方法将定义的布局动态加载进来。
最后修改activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_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>
我们使用
标签在布局中添加碎片,需要注意的是,这里我们还需要通过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:id="@+id/textView2"
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 {
@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;
}
}
然后修改下activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/right_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
LinearLayout>
将右边的碎片换成一个FrameLayout中,然后往FrameLayout中添加内容,从而实现动态添加碎片的功能。
修改MainActivity
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
textView = (TextView) findViewById(R.id.tetView);
ButtonOnClickListener listener = new ButtonOnClickListener();
button.setOnClickListener(listener);
replaceFragment(new RightFragment());
}
class ButtonOnClickListener implements View.OnClickListener{
@Override
public void onClick(View view) {
switch (view.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_fragment,fragment);
transaction.commit();
}
}
我们给左侧碎片按钮注册一个点击事件,然后调用replaceFragment()方法动态添加RightFragment这个碎片,当点击按钮时,又会调用replaceFragment()方法替换成AnotherRightFragment。结合replaceFragment()方法可以看出,动态添加碎片主要分为5步。
(1)创建待添加的碎片实例
(2)获取FragmentManager,在活动中可以直接通过调用getSupportFragmentManager()方法得到。
(3)开启一个事务,通过调用beginTransaction()方法开启。
(4)向容器内添加或替换碎片,一般使用replace()方法实现,需要传入容器的id和待添加的碎片实例。
(5)提交事务,调用commit()方法来完成。
在碎片中模拟返回栈
FragmentTransaction提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中,修改MainActivity代码
这里修改是在replaceFragment方法中添加了一行代码,所以下面只展示这个方法
private void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_fragment,fragment);
transaction.addToBackStack(null);//添加到返回栈
transaction.commit();
}
我们在事务提交之前调用了FragmentTransaction的addToBackStack()方法,他可以接收一个名字用于描述返回栈的状态,一般传入null
即可。
碎片与活动之间通信
为了方便碎片与活动之间进行通信,FragmentManager提供了一个类似于findViewById()的方法,专门用于从布局文件中获取碎片的实例。代码如下所示
RightFragment rightFragment = (RightFragment) getFragmentManager().findFragmentById(R.id.right_fragment);
//获取碎片实例
碎片的生命周期
和活动一样,碎片也有自己的生命周期,并且它和活动的生命周期实在是太像了。
同样的,Fragment类中也提供了一系列的回调方法,已覆盖碎片生命周期的每一个环节,其中活动中有的回调方法,碎片中几乎都有,不过碎片还提供一些附加的回调方法,那我们就重点看一下这几个回调。
onAttch(),当碎片和活动建立关联的时候调用。
onCreateView。为碎片创建视图(加载布局)时调用
onActivityCreated(),确保与碎片相关联的活动一定已经创建完毕的时候调用。
onDestroyView()。当与碎片关联的视图被移除的时候调用
onDetach()。当碎片与活动解出关联的时候调用