Android学习——Fragments

Fragments

1.Fragments简介

Fragment是Activity中用户界面的一个行为或者一个部分。你可以在单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用。你可以认为Fragment是Activity的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在Activity运行时添加或者删除。

两个概念:
Fragment、宿主
Fragment的生命周期直接受其宿主Activity的生命周期的影响。例如,一旦Activity被暂停,它里面的所有Fragment也被暂停;一旦Activity被销毁,它里面的所有Fragment也被销毁。

2.设计原理

Android在3.0(11)版本中引入了Fragment的概念
有了Fragment,你可以不必去管理视图体系的复杂变化。通过将activity的布局分割成若干个Fragment,可以在运行是编辑Activity的呈现,并且那些变化会被保存在由Activity管理的后台栈里面。
在这里插入图片描述

生命周期

在这里插入图片描述在这里插入图片描述

3.创建Fragment

要创建一个Fragment,必须创建一个Fragment的子类(或是继承自它的子类)。Fragment类的代码看起来很像Activity。它与Activity一样都有回调函数,例如onCreate()、onStarr()、onPause()、onStop()。事实上,如果你正在将一个现成的Android应用转而使用Fragment来实现,可以简单将代码从Activity的回调函数移植到各自的Fragment回调函数中。

除了基类Fragment,这里还有几个可能会继承的子类:

DialogFragment
ListFragment
PerferenceFragment

一般情况下,你至少需要实现以下几个生命周期方法:
onCreate()
在创建fragment时系统会调用此方法。在实现代码中,你可以初始化想要在fragment中保持的那些必要组件,当fragment处于暂停或者停止状态之后可重新启用它们。

onCreateView()
在第一次为fragment绘制用户界面时系统会调用此方法。为fragment绘制用户界面, 这个函数必须要返回所绘出的fragment的根View。如果fragment没有 用户界面可以返回空。

onPause()
系统会调用该函数作为用户离开fragment的第一个预兆(尽管这并不总意味着fragment被销毁)。在当前用户会话结束之前,通常要在这里提交任何应该持久化的变化(因为用户可能不再返回)。

添加用户界面

Fragment常被作为Activity用户界面的一部分,并且将本身的布局构建到Activity中去。

将Fragment添加到Activity有两种方式:

1. 在Activity 布局文件里声明Fragment

布局两个fragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/title_fragment"
        android:name="com.example.fragments.TitleFragment"></fragment>

    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        android:id="@+id/content_fragment"
        android:name="com.example.fragments.ContentFragment"></fragment>
</LinearLayout>

定义两个fragment类,title_fragment和content_fragment并绑定对应布局文件

package com.example.fragments;

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;

public class TitleFragment extends Fragment {

    //绑定对应布局文件
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.title_layout,container,false);
        return view;
    }
}

package com.example.fragments;

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;

public class ContentFragment extends Fragment {
    //绑定对应布局文件
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.content_layout,container,false);
        return view;
    }
}

对应的布局文件title_layout和content_layout

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


    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="时间" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="地点" />

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="人物" />
</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ddff">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="no data..."
        android:gravity="center"
        android:id="@+id/textView"/>

</LinearLayout>

在Main中声明获取fragment

package com.example.fragments;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    TitleFragment titleFragment;
    ContentFragment contentFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //通过FragmentManager(Fragment管理器)获取fragment
        titleFragment= (TitleFragment) getFragmentManager().findFragmentById(R.id.title_fragment);
        contentFragment= (ContentFragment) getFragmentManager().findFragmentById(R.id.content_fragment);
    }
}

在这里插入图片描述
2. 通过编码将Fragment添加到已存在的ViewGroup中

新建布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main2Activity">

    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:id="@+id/title_fragment"
        android:layout_weight="1"
        android:name="com.example.fragments.TitleFragment"/>
    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:id="@+id/content_fragment"
        android:layout_weight="3">

    </FrameLayout>

</LinearLayout>

在Main中添加Fragment

package com.example.fragments;

import android.annotation.SuppressLint;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Main2Activity extends AppCompatActivity {

    ContentFragment contentFragment;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        addContentLayout();
    }
    /*
    * 通过代码添加Fragment
    * */
    private void addContentLayout(){
        FragmentManager fn=getFragmentManager();
        //开启一个事务
        FragmentTransaction ft=fn.beginTransaction();
        contentFragment=new ContentFragment();
        //添加Fragment
        ft.add(R.id.content_fragment,contentFragment);
//        ft.remove();//删除
//        ft.replace();//替换
        ft.commit();
    }
}

在这里插入图片描述

4.管理Fragment

想要管理Activity中的Fragment,可以使用FragmentManager. 可以通过在Activity中调用getFragmentManager()获得。使用FragmentManager可以做如下事情,包括:

(1)使用findFragmentByld[] (用于在activity布局中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment (用于有界面或者没有界面的fragment)。

(2)使用popBackStack() (模仿用户的BACK命令)从后台栈弹出fragment。

(3)使用addOnBackStackChangedListener[)注册一个监听后台栈变化的监听器。

Fragment的传参方式

创建fragment对象,将参数封装保存到Bundle里,再用setArguments方法保存参数,如此使得参数不会丢失

public static PopBlankFragment getInstance(String title){
        PopBlankFragment p=new PopBlankFragment();
        Bundle b=new Bundle();
        b.putString("title",title);
        p.setArguments(b);
        return p;
    }

主界面

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".PopBackActivity">


    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="one"
        android:onClick="oneClick"
        android:textSize="24sp"/>

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:text="two"
        android:onClick="twoClick"
        android:textSize="24sp"/>

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/button4"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true">

    </FrameLayout>
</RelativeLayout>

新建Fragment在这里插入图片描述

package com.example.fragments;


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


/**
 * A simple {@link Fragment} subclass.
 */
public class PopBlankFragment extends Fragment {

    public PopBlankFragment(){}
    
    public static PopBlankFragment getInstance(String title){
        PopBlankFragment p=new PopBlankFragment();
        Bundle b=new Bundle();
        b.putString("title",title);
        p.setArguments(b);
        return p;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_pop_blank,container,false);
        TextView tv=view.findViewById(R.id.textView_text);
        tv.setText(getArguments().getString("title"));
        return view;
    }

}

对应的fragment布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".PopBlankFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment"
        android:textSize="24sp"
        android:id="@+id/textView_text"
        android:gravity="center"/>

</FrameLayout>

将fragment添加到activity中

package com.example.fragments;

import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class PopBackActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pop_back);

    }

    public void oneClick(View v){
        PopBlankFragment p1=PopBlankFragment.getInstance("one");
        FragmentTransaction ft=getFragmentManager().beginTransaction();
        ft.replace(R.id.content,p1);
        //把当前fragment添加到Activity栈
        ft.addToBackStack(null);
        ft.commit();
    }
    public void twoClick(View v){
        PopBlankFragment p2=PopBlankFragment.getInstance("two");
        FragmentTransaction ft=getFragmentManager().beginTransaction();
        ft.replace(R.id.content,p2);
        //把当前fragment添加到Activity栈
        ft.addToBackStack(null);
        ft.commit();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode==KeyEvent.KEYCODE_BACK){
            if (getFragmentManager().getBackStackEntryCount()==0){//判断返回栈里是否有返回值
                finish();
            }else {
                getFragmentManager().popBackStack();//出栈
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

5.处理Fragment事务

在activity中使用fragment的一大特点是具有添加、删除、替换,和执行其它动作的能力,以响应用户的互动。提交给activity的每一系列变化被称为事务,并且可以用FragmentTransaction中的APIs处理。

你也可以将每-个事务保存在由activity管理的后台栈中,并且允许用户导航回退fragment变更(类似于activity的导航回退)。

6.与Activity的交互

fragment可以通过getActivity0函数访问Activity,并且很容易的执行类似于查找activity布局中的视图的任务:View listView = getActivityl.findViewByld(R.id.ist);

activity能够调用fragment的函数findFragmentByld()或者findFragmentByTag(),从FragmentManager中获取FragmentExampleFragment fragment = (ExampleFragment) getFragmentManagerO).findFragmentByd(R id example _fragment);

fragment与activity共享事件
一个好方法是在fragment内部定义一个回调接口,并需要宿主activity实现它。
当activity通过接口接收到回调时,可以在必要时与布局中的其它fragment共享信息。

fragment布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main3Activity">

    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/menuFragment"
        android:name="com.example.fragments.MenuFragment"/>

    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:id="@+id/mainFragment"
        android:name="com.example.fragments.MainFragment"/>

</LinearLayout>

创建fragment类MenuFragment、Mainfragment绑定对应布局文件

package com.example.fragments;

import android.app.Activity;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * A simple {@link Fragment} subclass.
 */
public class MenuFragment extends Fragment implements View.OnClickListener {

    private MyMenuListener myMenuListener;

    public MenuFragment() {
        // Required empty public constructor
    }

    //myMenuListener实例化
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        myMenuListener=(MyMenuListener)activity;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragment_menu,container,false);
        view.findViewById(R.id.button_news).setOnClickListener(this);
        view.findViewById(R.id.button_music).setOnClickListener(this);
        return view;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.button_news:
                myMenuListener.changeValue("news");
                break;
            case R.id.button_music:
                myMenuListener.changeValue("music");
                break;
        }
    }

    //定义一个回调接口
    public static interface MyMenuListener{
        public void changeValue(String value);
    }

}
package com.example.fragments;

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

/**
 * A simple {@link Fragment} subclass.
 */
public class MainFragment extends Fragment {

    private TextView textView_value;
    public MainFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_main,container,false);
        textView_value=view.findViewById(R.id.textView_value);
        return view;
    }

    public void changeTextViewValue(String value){
        textView_value.setText(value);
    }

}

MianActivity

package com.example.fragments;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Main3Activity extends AppCompatActivity implements MenuFragment.MyMenuListener{

    private MenuFragment menuFragment;
    private MainFragment mainFragment;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        menuFragment=(MenuFragment) getFragmentManager().findFragmentById(R.id.menuFragment);
        mainFragment=(MainFragment) getFragmentManager().findFragmentById(R.id.mainFragment);
    }


    @Override
    public void changeValue(String value) {
        mainFragment.changeTextViewValue(value);
    }
}

在这里插入图片描述在这里插入图片描述在这里插入图片描述

7.PreferenceFragment

有时候,我们的程序需要提供一些选项功能,能让用户去定制化自己的使用风格。例如,允许用户是否自动保存登录信,允许用户设定某个页面的刷新时间等等。我们可以使用PreferenceActivity基 类去显示给用户一个选项设置的界面。在Android3.0或更高的版本上,可以使用PreferenceFragment类 去实现这个功能。

下面将展示如何去创建和使用PreferenceFragment。

  1. 在res文件来下面新建-一个xmI文件夹,在xmI文件夹下面新建一个文件: preferences.xml,用来描述你有那些选项。
  2. 在包路径下面新建一个类: Fragment继承PreferenceFragment。
  3. 从xmI文件加载选项addPreferencesFromResource(R.xml. preferences);
  4. 在本类中获取shared_pref文件
    String name=getPreferenceManager().getSharedPreferencesName();
    获取默认的属性配置
    SharedPreferences sp=PreferenceManager.getDefaultSharedPreferences(this); 
    String name=sp.getString("edittext_preference",""); 
    

新建preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="是否打开声音">
        <CheckBoxPreference android:key="checkbox_preference"
            android:title="打开声音"
            android:summary="设置打开声音后可以自动开启音乐"/>
    </PreferenceCategory>
    <PreferenceCategory android:title="城市">
        <EditTextPreference
            android:key="edittext_preference"
            android:title="昵称"
            android:summary="请输入你的昵称"
            android:dialogTitle="你的昵称"/>
        <ListPreference
            android:key="list_preference"
            android:title="城市名称"
            android:summary="请选择一个城市名称"
            android:entries="@array/city"
            android:entryValues="@array/city"
            android:dialogTitle="城市名称"/>
    </PreferenceCategory>
</PreferenceScreen>

城市列表

<string-array name="city">
        <item>温州</item>
        <item>宁波</item>
        <item>杭州</item>
        <item>台州</item>
        <item>衢州</item>
        <item>金华</item>
        <item>嘉兴</item>
    </string-array>

新建Fragment继承PreferenceFragment

package com.example.fragments;


import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
 * A simple {@link Fragment} subclass.
 */
public class PreferenceFragment extends android.preference.PreferenceFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.perference);
    }
}

获取默认的属性配置

package com.example.fragments;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class Main4Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main4);

        SharedPreferences sp= PreferenceManager.getDefaultSharedPreferences(this);
        String name=sp.getString("edittext_preference","");
    }

}

在这里插入图片描述在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/UUUUUltraman/article/details/89040731