Android基础学习(八)—— Fragment

|-- 简介
    ||-- 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



参考:

Android系列之Fragment(三)----Fragment和Activity之间的通信(含接口回调)

android高级开发必会系列

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值