|-- 简介
||-- Fragment是什么
||-- Fragment的由来
||-- Fragment的特性
|-- 在 Activity 中添加 Fragment
||-- 静态添加Fragment
||-- 动态添加Fragment
|-- Activity 与 Fragment 通信
||-- 使用Bundle
||-- 使用接口回调
|-- Fragment 生命周期
|-- Fragment + ViewPager 联合应用
Fragment
一、简介
1、Fragment是什么
碎片,是一种可以嵌入在 Activity 中的 UI 片段
2、Fragment的由来
Android3.0提出的,一开始的是为了平板电脑界面的动态灵活设计而使用
3、Fragment的特性
(1)和其它 view 不同,Fragment 具备生命周期
① 可在一个Activity中组合使用多个Fragment,从而构成多窗格的界面
② 可在多个Activity中重复使用一个Fragment
(2)必须委托在 Activity 中才能运行(必须有宿主Activity)
当一个Activity暂停/销毁时,它里面的Fragment也会暂停/销毁;当一个Activity运行时,它里面的Fragment可以独立操作
二、在 Activity 中添加 Fragment
1、静态添加Fragment
直接在 activity_main.xml 中的布局中添加 控件
2、动态添加Fragment
① Activity布局中放入碎片:通过添加 FrameLayout 布局来放置碎片
② 创建一个Fragment
public class Fragment1 extends Fragment{
private View root;
...
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
if(root == null){
root = inflater.inflate(R.layout.frame_1, container, false);
}
textView = root.findViewById(R.id.textView);
...
return root;
}
}
③ Fragment的添加、移除等都是通过FragmentTransaction(由 getSupportFragmentManager.beginTransaction() 得到)来完成的
transation.replace(R.id.frameLayout, fragment1); //framelayout布局来放置碎片
transation.commit();
注意:
可在碎片中模拟返回栈
FragmentTransation.addToBackStack() 方法,Fragment会逐个添加到栈中,点击回退时,再逐个出栈
三、Activity 与 Fragment 通信
注意:Activity 和 Fragment 各自存在于一个独立的类当中
1、Activity发送信息给Fragment——使用Bundle
原生方案:Bundle(可理解为 Android 里面保存数据的一个独立的类)
bundle.putXxx(…) 可以看到 Bundle 可以 put 的数据类型
看下Parcelable?(Android序列化)
在Activity中:
Bundle bundle = new Bundle();
bundle.putString("message", " 我喜欢享学课堂");
BlankFragment1 bf = new BlankFragment1();
bf.setArguments(bundle);
BlankFragment1中拿到Activity中的值:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getArguments();
String string = bundle.getString("message");
Log.d(TAG, "onCreate: " + string);
}
2、Java语言中类与类自己通信常用方案:接口
(1)Fragment向Activity传递数据
1)创建回调接口
public interface IFragmentCallback{
void sendMsgToActivity(String msg);
String getMsgFromActivity(String msg);
}
2)Fragment1 进行回调赋值
private IFragmentCallback fragmentCallback;
public void setFragmentCallback(IFragmentCallback callback){
fragmentCallback = callback;
}
//可在button中做触发事件
fragmentCallback.sendMsgToActivity("hello, I'm from Fragment");
3)Activity通过设置接口回调接收数据
BlankFragment1 bf = new BlankFragment1();
bf.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public String getMsgFromActivity(String msg) {
return "hello, I am from activity";
}
});
(2)Activity向Fragment传递数据
1)先创建回调接口IFragmentCallback
public interface IFragmentCallback {
void sendMsgToActivity(String msg);
String getMsgFromActivity(String msg);
}
2)Fragment进行回调赋值
private IFragmentCallback fragmentCallback;
public void setFragmentCallback(IFragmentCallback callback){
fragmentCallback = callback;
}
//可在button中做触发事件
String msg = fragmentCallback.getMsgFromActivity("null");
Toast.makeText(BlankFragment1.this.getContext(), msg, Toast.LENGTH_SHORT).show();
3)Activity通过设置接口回调接收数据
BlankFragment1 bf = new BlankFragment1();
bf.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
}
@Override
public String getMsgFromActivity(String msg) {
return "hello, I am from activity";
}
});
(3)其他方案: eventBus、LiveData
四、Fragment 生命周期
- onAttach():和 Activity 捆绑,因为Fragment是依托于Activity运行的
- onDetach():和 Activity 解绑
- onCreate():创建 Fragment。在此函数里面通常对Activity传来的Bundle解析
- onDestroy():销毁Fragment
- onCreateView():创建UI
- onActivityCreated():意味着Activity创建已经创建了
(1)打开界面
onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
(2)按下Home键
onPause() -> onStop()
(3)重新打开界面
onStart() -> onResume()
(4)按后退键
onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()
五、Fragment + ViewPager 联合应用
Activity : 界面宿主
Fragment:在宿主上显示
本小节将简单实现底部含Tab的页面切换效果(类似微信首页)
一、实现页面切换
1、activity_main.xml(简写)
<LinearLayout>
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/id_viewpager">
</androidx.viewpager2.widget.ViewPager2>
</LinearLayout>
2、所有的Fragment都将在ViewPager中
MainActivity.java
ViewPager2 viewPager;
//onCreate
setContentView(R.layout.activity_main);
initPager();
//initPager
private void initPager(){
viewPager = findViewById(R.id.id_viewPager);
List<Fragment> fragments = new ArrayList<>();
fragments.add(BlankFragment.newInstance("微信聊天"));
fragments.add(BlankFragment.newInstance("通讯录"));
fragments.add(BlankFragment.newInstance("发现"));
fragments.add(BlankFragment.newInstance("我的"));
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), getLifecycle(), fragments);
viewPager.setAdapter(pagerAdapter)
}
3、MyFragmentPagerAdapter
public class MyFragmentPagerAdapter extends FragmentStateAdapter{
List<Fragment> fragmentList = new ArrayList<>();
public MyFragmentPagerAdapter(FragmentManager fragmentManager, Lifecycle lifeCycle, List<Fragment> fragments){
super(fragmentManager, lifeCycle);
fragmentList = fragments;
}
@Override
public Fragment createFragment(int position){
return fragmentList.get(position);
}
@Override
public int getItemCount(){
return fragments.size();
}
}
4、BlankFragment.java
public class BlankFragment extends Fragment{
private static final String ARG_PARAM1 = "param1";
View rootView;
private String mTextString;
public BlankFragment(){
}
//用于复用Fragment,因为这里用到多个相似的Fragment
public static BlankFragment newInstance(String param1){
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(getArguments() != null){
mTextString = getArguments().getString(ARG_PARAM1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
if(rootView == null){
rootView = inflater.inflate(R.layout.fragment_blank, container, false);
}
initView();
return rootView;
}
private void initView(){
TextView textView = rootView.findViewById(R.id.text);
textView.setText(mTextString);
}
}
fragment_black.xml
<FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_heigth="match_parent"
android:gravity="center"
android:textSize="36sp"
android:id="@+id/text"
android:text="@string/hello_blank_fragment"/>
</FrameLayout>
二、实现底部Tab
目前网上关于实现底部Tab有多种方案,目前较为常用的是直接通过 BottomNavigationView 组件来实现。
自己来写一个Tab。
1、新建一个 bottom_layout.xml
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/gray">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical"
android:id="@+id/id_tab_weixin">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:background="@drawable/tab_weixin"
android:id="@+id/tab_iv_weixin">
</ImageView>
<TextView
android:layout_width=32dp
android:layout_height="wrap_content"
android:gravity="center"
android:text="微信"
android:id="@+id/text_weixin">
</TextView>
</LinearLayout>
<LiearLayout><!--..通讯录..--></LiearLayout>
<LiearLayout><!--..发现..--></LiearLayout>
<LiearLayout><!--..我的..--></LiearLayout>
</LinearLayout>
tab_weixin.xml
<selector>
<item android:drawable="@drawable/weixin_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/weixin_unpressed"
</selector>
在activity_main.xml中添加进来 bottom_layout.xml
<LinearLayout>
...
<include layout="@layout/bottom_layout"></include>
</LinearLayout>
2、在MainActivity中添加内容:
class MainActivity implements View.OnClickListener{
private LinearLayout llChat, llContact, llFind, llProfile;
private ImageView ivChar, ivContacts, ivFind, ivProfile, ivCurrent;
//在onCreate函数中
void onCreate(){
initPager();
initTabView();
}
void initTabView(){
...//一系列的findViewById,并设置监听器
ivChat.setSelected(true); //设置底部Tab初始状态
ivCurrent = ivChat;
}
void initPager(){
viewPager = findViewById(R.id.id_viewpager);
ArrayList<Fragment> fragments = new ArrayList<>();
fragments.add(BlankFragment.newInstance("微信聊天"));
fragments.add(BlankFragment.newInstance("通讯录"));
fragments.add(BlankFragment.newInstance("发现"));
fragments.add(BlankFragment.newInstance("我"));
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), getLifecycle(), fragments);
viewPager.setAdapter(pagerAdapter);
//为滑动ViewPager添加效果
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback()){
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageSelected(int position){
super.onPageSelected(position);
changeTab(position);
}
@Override
public void onPageScrollStateChanged(int state){
super.onPageScrollStateChanged(state);
}
}
}
//滑动ViewPager,或点击下方Tab,都会执行changeTab
private void changeTab(int position){
ivCurrent.setSelected(false);
switch(position){
case R.id.tab_chat: //选择第0个Tab
viewPager.setCurrentItem(0);
case 0: //滑动到第0个ViewPager,使得下面的Tab为Selected状态
ivChat.setSelected(true);
ivCurrent = ivChat;
break;
case R.id.tab_contacts:
viewPager.setCurrentItem(1);
case 1:
ivContacts.setSelected(true);
ivCurrent = ivContacts;
break;
case R.id.tab_find:
viewPager.setCurrentItem(2);
case 2:
ivFind.setSelected(true);
ivCurrent = ivFind;
break;
case R.id.tab_profile:
viewPager.setCurrentItem(3);
case 3:
ivProfile.setSelected(true);
ivCurrent = ivProfile;
break;
}
}
void onClick(View view){
changeTab(view.getId());
}
}
适配器中FragmentPagerAdapter 和 FragmentStatePagerAdapter有区别
jetpack 享学高阶课程里面有介绍 2021年最新的app使用mv vm模式,里面会大量使用 jetpack
参考: