Android Studio开发学习(十三)——Fragment

一、前提

Fragment作为Android最基本,最重要的基础概念之一,在开发中经常会和他打交道。Fragment有自己的生命周期,依赖于Activity,可以与Activity的相互获取(Fragment通过getActivity()获取Activity;Activity通过FragmentManger的findFragmentById()或findFragmentByTag()获取Fragment),与Activity的多对多关系

二、目标

Fragment

三、内容

1、Fragment在Activity中的基本运行

先在activity_main中添加如下布局文件,一个按钮和一个布局管理器

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.sunny.fragment.MainActivity">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="change"
        />

    <LinearLayout
        android:id="@+id/fl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/btn"
        >
    </LinearLayout>
</RelativeLayout>

分别建立两个新的java文件,且其中的代码相同,这里展示一个

在xml文件中添加一个TextView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    >
    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#000000"
        android:textSize="20sp"
        android:text="helloB"
        android:gravity="center"
        />
</LinearLayout>

在java文件中添加

package com.example.sunny.fragment;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by Sunny on 2020/4/24.
 */
public class BFragment extends Fragment {
    private TextView textView;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragmentb,container,false);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        textView= (TextView) view.findViewById(R.id.tv);
    }
}

在此处我们可以看到java文件继承Fragment

且常用的两种方法是:

onCreateView()方法,该方法返回视图文件,相当于Activity中onCreate方法中setContentView一样

onViewCreated()方法,该方法当view创建完成之后的回调方法

说白了就是一个用于创造,一个用于运用

在onCreateView()中首先还是找到为它写的布局文件,返回视图文件

在onViewCreated()中找到其视图文件中的各类控件进行使用

在MainActivity中添加

package com.example.sunny.fragment;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private AFragment aFragment;
    private BFragment bFragment;
    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.btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bFragment == null) {
                    bFragment = new BFragment();
                }
                //返回FragmentManager,用于与与此活动关联的片段进行交互;;在与这个片段管理器关联的片段上启动一系列编辑操作
                getFragmentManager().beginTransaction().replace(R.id.fl, bFragment).commitAllowingStateLoss();
            }
        });

        //实例化AFragment
        //aFragment=AFragment.newInstance("hello");
        aFragment=new AFragment();
        //把AFragment添加到Activity中,记得调用commit
        getFragmentManager().beginTransaction().add(R.id.fl,aFragment).commitAllowingStateLoss();
    }


逻辑就是:首先实例化一个Fragment,将Fragment添加到Activity中,通过按钮点击跳转至另一个Fragment

getFragmentManager().beginTransaction()是固定操作,关键在于你是想要替换还是添加,都是将fragment的实例传给之前布局的LinearLayout中,最后提交,一般使用commitAllowingStateLoss()方法进行提交因为commmit()方法有时会报错

2、向Fragment传递参数

在AFragment中添加一个静态方法,在该方法中进行实例化并且返回fragment

setArguments()方法:为这个片段提供构造参数。这只能在片段被连接到它的活动之前调用;也就是说,您应该在构建片段之后立即调用它。这里提供的参数将在片段销毁和创建之间保留。

    public static  AFragment newInstance(String title){
        AFragment fragment=new AFragment();
        Bundle bundle=new Bundle();
        bundle.putString("title",title);
        fragment.setArguments(bundle);
        return fragment;
    }

在onViewCreated()方法中添加,判断之前创建的是否存在,若存在则可赋值

if(getArguments()!=null){
            textView.setText(getArguments().getString("title"));
        }

最后在MainActivity中将之前实例化的语句改为

aFragment=AFragment.newInstance("hello");

3、Fragment回退栈

首先要对代码进行改动,去掉activity_main中的按钮,将它放置在AFragment的布局文件中,并且在添加一个按钮

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    >

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更换为BFragment"
        />

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更换文字内容"
        />

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#000000"
        android:textSize="20sp"
        android:text="helloA"
        android:gravity="center"
        />
</LinearLayout>

在MainActivity中删除Button的点击事件,添加一个标记

package com.example.sunny.fragment;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private AFragment aFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       //实例化AFragment
        aFragment=AFragment.newInstance("hello");
        //把AFragment添加到Activity中,记得调用commit
        getFragmentManager().beginTransaction().add(R.id.fl,aFragment,"a").commitAllowingStateLoss();
    }
}

注意:多了的那个"a"表示一个标记,可使用它来找寻相应的片段

在AFragment的java文件中的onViewCreated()中添加


        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bFragment == null) {
                    bFragment = new BFragment();
                }
                Fragment fragment=getFragmentManager().findFragmentByTag("a");
                if (fragment!=null){
                    getFragmentManager().beginTransaction().hide(fragment).add(R.id.fl, bFragment).addToBackStack(null).commitAllowingStateLoss();
                }else{
                    getFragmentManager().beginTransaction().replace(R.id.fl, bFragment).addToBackStack(null).commitAllowingStateLoss();
                }
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.setText("new text");
            }
        });

第一个按钮的作用是点击后调到下一个Fragment中,首先判断是否存在bFragment,若不存在则实例化一个,若存在,则先找是否发现标记a,若标记a的片段存在,则将它隐藏后添加新的Fragment,若不存在,则直接进行替换

addToBackStack(null)是将此事务添加到后堆栈。这意味着事务将在提交后被记住,并将在稍后弹出堆栈时反转其操作。他其中的参数是一个String name表示此回堆栈状态的可选名称,或null;一般写null;意思也就是说,添加这个方法后,你使用返回键后就会返回你的上一步操作,否则会直接回到你的首次操作,比如你有一个主页面,点击按钮后疯狂跳转,如果没有添加此方法,则点击返回键直接返回主页面,中间所有的跳转页面都不会再显示

hide()表示隐藏现有的片段。这只与那些视图已被添加到容器中的片段相关,因为这将导致视图被隐藏。这样你即使点击修改文字后,再进入BFragment后,返回看到的还是修改后的文字否则。你不管怎样更改文字内容,更换Fragment后返回看到的永远都是最初的文字,如下图

第二个按钮的作用是点击后文字改变,整个的效果

4、二者之间的通信

Fragment发送一个消息给Activity,让他去执行,利用回调接口的方法

先在AFragment的xml文件中在添加一个按钮

    <Button
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="给ACTIVITY传递消息"
        />

在AFragment的中写一个接口

private IOnMessageClick listener;
 
public interface IOnMessageClick{
        void onClick(String text);
    }

在MainActivity中实现这个接口,并且重写方法

package com.example.sunny.fragment;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements AFragment.IOnMessageClick{
    private AFragment aFragment;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView= (TextView) findViewById(R.id.title);
       //实例化AFragment
        aFragment=AFragment.newInstance("hello");
        //aFragment=new AFragment();
        //把AFragment添加到Activity中,记得调用commit
        getFragmentManager().beginTransaction().add(R.id.fl,aFragment,"a").commitAllowingStateLoss();
    }
    
    @Override
    public void onClick(String text) {
        textView.setText(text);
    }
}

在AFragment中,当Fragment依附于Activity时有一个方法,是onAttach(),表示当片段首次附加到其上下文时调用。

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            listener= (IOnMessageClick) context;
        }catch(ClassCastException e){
            e.printStackTrace();
        }

    }

最后在新的按钮的点击事件中添加代码

listener.onClick("succeed");

四、总结

Fragment相对来说功能强大,与Activity相辅相成,很重要的一个知识点,也比较复杂

原创文章 30 获赞 5 访问量 1897

猜你喜欢

转载自blog.csdn.net/qq_41890177/article/details/105739803
今日推荐