Android Fragment
01 Fragment 的产生
我们一般认为 Fragment 是小的 activity
3.0 产生 Fragment
手机 底部 Item 点一个 Item 出现一个 Fragment
什么是 Fragment
和其他view 不同
- 具备生命周期
- 在一个activity中组合使用多个 Fragment ,从而构造多窗格的界面。
- 在多个activity中重复使用,重复利用
- 可以自己去接受输入事件,同样可以动态的增加和移除某一些Fragment
- 必须委托在activity中才能运行 。
- fragment 生命周期依赖于 activity activity暂停,fragment也暂停
- activity运行的时候,fragment可以独立的运行和操作
可以将 Fragment 片段 视为activity 模块化组成部分 ,变成一个部分(子activity)。
Fragment 使用方法
-
新建一个Fragment
-
public class BlankFragment1 extends Fragment
-
-
定义一个 Fragment xaml
-
<TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="40dp" android:text="@string/hello_blank_fragment" /> <Button android:layout_width="match_parent" android:layout_height="40dp" android:text="how are you?" android:id="@+id/btn" />
-
-
fragment 并不和 activity 一样
-
通过inflater 解析成一个 view
-
activity 通过 setContentView 解析
-
//生命周期函数 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (root == null) { root = inflater.inflate(R.layout.fragment_blank_fragment1, container, false); }
-
-
Fragment 就是小型 activity 可以直接操作组件
-
textView = root.findViewById(R.id.tv); button = root.findViewById(R.id.btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { textView.setText("good,how u doing?"); } });
-
-
把 创建好的 fragment 放进 mainactivity
-
必须 加 id,
-
<fragment android:name="com.example.myapplication.BlankFragment1" android:layout_width = "match_parent" android:layout_height = "match_parent" android:id="@+id/fragment1"/>
-
-
在 activity 增加两个 fragment
<fragment android:name="com.example.myapplication.BlankFragment1"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_weight = "1"
android:id="@+id/fragment1"/>
<fragment android:name="com.example.myapplication.BlankFragment2"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_weight = "1"
android:id="@+id/fragment2"/>
动态添加 Fragment
- 创建一个待处理的fragement
- 获取FragmentManger,一般都是通过getSupportfragmentManager()
- 开启一个事务transaction,一般调用fragmentManger 的 beginTransaction
- 使用transaction 进行 fragment 的替换
- 提交事务
-
创建 两个 Button 和 FrameLayout(点击按钮,fragment 替换 Frame Layout)
-
main_activity 布局
-
<Button android:id="@+id/btn1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/change" /> <Button android:id="@+id/btn2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/replace"/> <FrameLayout android:id="@+id/frameLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorAccent"/>
-
-
设置按钮点击事件
-
实现按钮点击事件有两种
-
匿名内部类(就像前面实现的那样,传输 new View.OnClickListener 对象 )
-
实现接口
-
public class MainActivity extends AppCompatActivity implements View.OnClickListener
-
-
-
Button button = findViewById(R.id.btn1); button.setOnClickListener(this); Button button2 = findViewById(R.id.btn2); button2.setOnClickListener(this); @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn1: replaceFragment(new BlankFragment()); break; case R.id.btn2: replaceFragment(new ItemFragment()); } }
-
-
实现 动态切换 fragment
-
//获得 fragment 管理类 FragmentManager fragmentManager = getSupportFragmentManager(); // 获得事务 FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.frameLayout,fragment); // fragment 压入栈,返回的时候,一个一个弹出 transaction.addToBackStack(null); // 提交之后才能运行 transaction.commit();
- beginTransaction 开始事务
-
-
Activity 与 Fragment 通信
-
两个相互独立的类
-
都是用来展示 UI的
-
独立的类 怎么进行 通信呢?
- Activity 与 Fragment 通信
- Activity 与 Activity 通信
- Fragment 与 Activity 通信
- Fragment 与 Fragment 通信
-
先学习 Activity 与 Fragment 通信
-
原生方案 Bundle n. 束;捆
-
创建 Bundle 对象
-
Bundle bundle = new Bundle(); bundle.putString("message","你好呀Fragment,我是activity,"); BlankFragment blankFragment = new BlankFragment(); blankFragment.setArguments(bundle); replaceFragment(blankFragment);
-
-
你可以在 fragement 任何地方获取 message,以生命周期为例
-
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 返回 activity传进去的 bundle Bundle bundle = this.getArguments(); String string = bundle.getString("message"); Log.e("leo","传进来的string:"+string); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } }
-
-
-
-
另一种通信方案 : 接口(Java 语言中类与类自己通信的方案)
-
定义一个接口类(面向对象原则:面向接口编程)
-
public interface IFragmentCallback { void sentMsgToActivity(String string); String getMsgFromActivity(String msg); }
-
通过接口 对象 实现弱关联
-
-
-
在 Fragment里面定义一个承接 接口类型对象的函数,接口类型对象的值来自 Avtivity,在Activity 里面创建 Fragment对象,调用Fragment 里面的接口方法里 new 接口类型对象(匿名内部类),把值赋值给 Fragment 里面的变量
-
Fragment
-
//定义一个callback函数 activity 给他赋值 private IFragmentCallback fragmentCallback; // activity 调用这个函数赋值 public void setFragmentCallback(IFragmentCallback callback){ fragmentCallback = callback; }
-
-
Activity
-
// 通过对象 调用 callback 方法赋值 //调用接口对象,new 匿名内部类 blankFragment.setFragmentCallback(new IFragmentCallback() { @Override public void sentMsgToActivity(String string) { } @Override public String getMsgFromActivity(String msg) { return null; } });
-
mainactivity里面
-
// 通过对象 调用 callback 方法赋值 //调用接口对象,new 匿名内部类 blankFragment.setFragmentCallback(new IFragmentCallback() { @Override public void sentMsgToActivity(String msg) { Toast.makeText(MainActivity.this,msg,Toast.LENGTH_LONG).show(); }
-
-
-
-
实现fragment 发布消息 给 activity
-
fragment 里面
-
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(rootView == null) { rootView = inflater.inflate(R.layout.fragment_blank, container, false); } Button button = rootView.findViewById(R.id.btn3); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { fragmentCallback.sentMsgToActivity("hello,I'm from fragment"); } }); // Inflate the layout for this fragment return rootView; }
-
-
观察者设计模式,发布订阅
fragment 可以 观测activity 的变化,activity发布的消息是我感兴趣的消息,我就接受到
封装好的方案 : eventBus, LiveData
Fragment 生命周期
fragment 执行 依托 activity 执行。
-
onAttach() 和 activity 捆绑
-
onCreat() fragment 创建 对 activity 传来的bundle进行解析就要在oncreat里面进行
-
onCreatView 对fragmentUI的设计
-
onActivityCreated() Activity 创建
-
onStart
-
onResume 重新开始,继续;重新回到
-
onPause 暂停;间歇 UI 状态复位
-
onStop
-
onDestoryView
-
onDestory fragment 销毁
-
onDetach() 和 activity 解绑
难点 每次调用并不严格按照顺序
- 打开界面
- onCreate() -> onCreateView -> onActivityCreated() -> onStart -> onResume
- 按下主屏键
- onPause -> onStop
- 重新打开界面
- onStart -> onResume()
- 按下退键
- onPause() -> onStart -> onDestoryView -> onDestory -> onDetach()
生命周期总结
-
将来开发者会围绕fragment生命周期花很多时间来解决问题
-
Fragment 的使用一定需要在生命周期函数onAttach 和 onDetach之间
-
Fragment 的使用一定要遵守生命周期管理的规划,在正确的地方写恰当的代码
Fragment 与 ViewPager的联合应用
ViewPager + Fragment 形成翻页效果
减少用户的操作:点击层面越少越好
viewPager1 和 viewPager2 的区别
-
viewpager1 是使用完全自定义的 group
-
viewPager2 也是group 对 recycleView 的封装 说白了就是 recyleview 自带 懒加载 功能
-
设置viewpager 布局
-
<androidx.viewpager.widget.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/viewPager" android:background="@color/colorAccent"/>
-
-
viewpager 是一个容器,需要适配很多不同的参数,所以在 activity 创建 viewpager对象还需要setAdapter()
-
ViewPager2 viewPager = findViewById(R.id.viewPager); ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(); viewPager.setAdapter(viewPagerAdapter);
-
-
创建Adaptor类
-
class ViewPagerAdapter extends RecyclerView.Adapter { @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return null; } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { } @Override public int getItemCount() { return 0; } }
-
-
适配的内容是一个单独界面,创建界面
-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/action_container"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tvTitle" android:layout_centerInParent="true" android:textColor="#ff4532" android:textSize="32dp" android:text="Hello"/> </RelativeLayout>
-
-
adapter 解析item_pager 组件
-
// 解析 item_pager class ViewPagerViewHolder extends RecyclerView.ViewHolder{ TextView mtv; RelativeLayout mContainer; public ViewPagerViewHolder(@NonNull View itemView) { super(itemView); mContainer = itemView.findViewById(R.id.container); mtv = itemView.findViewById(R.id.tvTitle); } }
-
-
把 组件加到 view上 先解析 Item_pager .xml 成 一个 view
public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //解析 xml 返回 view return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager,parent,false)); }
-
设置文字和颜色
-
public ViewPagerAdapter(){ titles.add("Hello"); titles.add("Kity"); titles.add("A"); titles.add("B"); titles.add("C"); titles.add("D"); titles.add("E"); titles.add("F"); titles.add("G"); titles.add("H"); } colors.add(R.color.white); colors.add(R.color.red); colors.add(R.color.colorAccent); colors.add(R.color.colorPrimary); colors.add(R.color.balck); colors.add(R.color.colorPrimary); colors.add(R.color.red); colors.add(R.color.white); colors.add(R.color.balck);
-
-
设置页数
-
@Override public int getItemCount() { return 10; }
-
-
传入文字和颜色
-
@Override public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) { holder.mtv.setText(titles.get(position)); } holder.mContainer.setBackgroundResource(colors.get(position));
-
总结
一般流程:
- 定义 ViewPager
- 为Viewpager 构建 Adapter
- 创建Adapter 并继承RecyclerView.Adapter
- 构建ViewPager 要展示页面的 ViewHolder
- 实现必须的方法
Fragment 与 ViewPager 的联合应用
ViewPager + Fragment 形成翻页效果‘
- activity是数组,fragment是数组之上的结构
MV VM : jetpack 扩展
模拟微信页面
方案1 :ButtomNavigationView