Android的Fragment介绍

前言

    fragment是从android3.0开始提出来的,用来支持大屏幕设备的ui设计。通过将activity划分为多个fragment,不仅提高了设计的灵活性,而且可以在程序运行时改变它们的特征,比如动态的修改,替换已有的fragment等等。

    fragment的角色是相当于activity中ui的一个子集或者说是activity中的一个模块,可以通过组合多个fragment来构造一个多个面板的界面。由于fragment嵌入在activity中,因此它的生命周期受到activity的影响,一旦activity停掉,它里面所有的fragment也都会被摧毁。

    可以在activity的布局文件中通过声明<fragment>标签来填充它的布局,同时也可以通过代码将它加到已经存在的ViewGroup中,因为fragment布局实际上就是ViewGroup的子树。

新建一个Fragment

    首先需要了解的是fragment的生命周期,如下图所示:

fragment_lifecycle

可以看出调用的先后顺序是:

  • onCreate  这里可以用来初始化一些当fragment停掉时候你仍想保存的组件
  • onCreateView  这里可以用来绘制fragment的用户界面,因此必须返回一个view
  • onPause  当fragment被移走或者替换时调用,可以在这里commit changes

一般可以继承fragment类来创建自己的fragment,同时亦有几个有用的fragment基类供我们继承:

  1. DialogFragment  也就是浮动在Activity上面的fragment,这种对话框可以供用户返回,便于管理,是google推荐的做法。
  2. ListFragment  就是包含ListView的Fragment,用来显示列表等。
  3. PreferenceFragment  可以用来显示用户选项的设置。

一般来说,要创建Fragment,第一步就是创建一个Fragment的子类,并在onCrateView方法中填充布局:

public static class ExampleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragment//resourceID,ViewGroup, whether the inflated layout should be //attached to the ViewGroup during inflationreturn inflater.inflate(R.layout.example_fragment, container, false);}
}

第二步就是将fragment添加到activity中,可以在activity的布局文件中声明,如:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><fragment android:name="com.example.news.ArticleListFragment"android:id="@+id/list"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent" /><fragment android:name="com.example.news.ArticleReaderFragment"android:id="@+id/viewer"android:layout_weight="2"android:layout_width="0dp"android:layout_height="match_parent" />
</LinearLayout>

这样一来,当创建activity的布局时,就会初始化每一个fragment,并且调用它们的onCreateView方法,获取fragment的布局,然后插入到ViewGroup下面。

除了使用布局文件之外,还可以用程序进行添加:

FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

前两行用来获取碎片事务FragmentTransaction,后三行用来添加一个fragment,add方法的第一个参数是要放置的ViewGroup,第二个参数是要添加的fragment。

Fragment的管理

通过fragmentManager可以做一下事情:

  • 获取fragment,通过findFragmentById或者findFragmentByTag
  • 将Fragment从栈中移除,通过popBackStack方法
  • 为back stack注册监听器

相信这里的细节还有很多,暂时先不介绍。

Fragment的事务

    fragment的一大亮点就是可以动态增加,删除,替换fragment,而这是通过fragmentTransaction来实现的。一旦获取了事务的实例,就可以通过调用add,remove,replace方法完成上述功能,接下来通过commit方法提交事务就可以了。

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);// Commit the transaction
transaction.commit();

    除此之外还可以调用addToBackStack方法将fragment添加到back stack中,用户按下返回键时,就会跳到back stack顶部的fragment。调不调用它的区别在于,如果没有它,fragment被remove后就彻底销毁了,再也不能恢复,如果调用了它,fragment就不会销毁而是stop,这样就可以恢复,因为fragment的状态都被保存在了back stack上面。

    commit方法的作用是调度到activity的主线程中执行,并且事务的提交必须要在onSaveInstanceState之前。

和Activity的通信

    fragment也是可以和它所在的activity通信的,比如可以通过getActivity()方法得到所在的activity,相应的,activity也可以调用FragmentManager的findFragmentById方法获取某一个fragment的引用。

    有时候需要在fragment和activity之间共享事件,如activity有一个fragment,是用来显示文章的列表的,当用户点击了某一项,activity需要检测到这个事件,同时更改另一个fragment从而显示出相应的文章内容。这时可以这么做,在fragment中定义事件监听的接口,然后让activity实现这个接口。然后,这个fragment就可以调用接口中的某些方法来通知activity了。fragment中可以在onAttach里面将activity强制转化为接口的实现类,从而确保能成功调用接口中的方法。

public static class FragmentA extends ListFragment {OnArticleSelectedListener mListener;...// Container Activity must implement this interfacepublic interface OnArticleSelectedListener {public void onArticleSelected(Uri articleUri);}...@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);try {mListener = (OnArticleSelectedListener) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");}}...@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {// Append the clicked item's row ID with the content provider UriUri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);// Send the event and Uri to the host activitymListener.onArticleSelected(noteUri);}...
}

例子

   该例子来源于api demo,用到了很典型的两个fragment,一个是TitlesFragment,用来显示一个列表,另一个是DetailsFragment,用来显示选中item的详细信息。此外,该程序还考虑到了屏幕的横竖屏问题,如果是竖屏的话,没有足够的地方显示第二个Fragment,就单独启动一个Activity。源码如下:

/*** Demonstration of using fragments to implement different activity layouts.* This sample provides a different layout (and activity flow) when run in* landscape.*/
public class FragmentLayout extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.fragment_layout);}/*** This is a secondary activity, to show what the user has selected* when the screen is not large enough to show it all in one activity.*/public static class DetailsActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getResources().getConfiguration().orientation== Configuration.ORIENTATION_LANDSCAPE) {// If the screen is now in landscape mode, we can show the// dialog in-line with the list so we don't need this activity.
                finish();return;}if (savedInstanceState == null) {// During initial setup, plug in the details fragment.DetailsFragment details = new DetailsFragment();details.setArguments(getIntent().getExtras());getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();}}}/*** This is the "top-level" fragment, showing a list of items that the* user can pick.  Upon picking an item, it takes care of displaying the* data to the user as appropriate based on the currrent UI layout.*/public static class TitlesFragment extends ListFragment {boolean mDualPane;int mCurCheckPosition = 0;@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);// Populate list with our static array of titles.setListAdapter(new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));// Check to see if we have a frame in which to embed the details// fragment directly in the containing UI.View detailsFrame = getActivity().findViewById(R.id.details);mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;if (savedInstanceState != null) {// Restore last state for checked position.mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);}if (mDualPane) {// In dual-pane mode, the list view highlights the selected item.
                getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);// Make sure our UI is in the correct state.
                showDetails(mCurCheckPosition);}}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putInt("curChoice", mCurCheckPosition);}@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {showDetails(position);}/*** Helper function to show the details of a selected item, either by* displaying a fragment in-place in the current UI, or starting a* whole new activity in which it is displayed.*/void showDetails(int index) {mCurCheckPosition = index;if (mDualPane) {// We can display everything in-place with fragments, so update// the list to highlight the selected item and show the data.getListView().setItemChecked(index, true);// Check what fragment is currently shown, replace if needed.DetailsFragment details = (DetailsFragment)getFragmentManager().findFragmentById(R.id.details);if (details == null || details.getShownIndex() != index) {// Make new fragment to show this selection.details = DetailsFragment.newInstance(index);// Execute a transaction, replacing any existing fragment// with this one inside the frame.FragmentTransaction ft = getFragmentManager().beginTransaction();if (index == 0) {ft.replace(R.id.details, details);} else {ft.replace(R.id.a_item, details);}ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);ft.commit();}} else {// Otherwise we need to launch a new activity to display// the dialog fragment with selected text.Intent intent = new Intent();intent.setClass(getActivity(), DetailsActivity.class);intent.putExtra("index", index);startActivity(intent);}}}/*** This is the secondary fragment, displaying the details of a particular* item.*/public static class DetailsFragment extends Fragment {/*** Create a new instance of DetailsFragment, initialized to* show the text at 'index'.*/public static DetailsFragment newInstance(int index) {DetailsFragment f = new DetailsFragment();// Supply index input as an argument.Bundle args = new Bundle();args.putInt("index", index);f.setArguments(args);return f;}public int getShownIndex() {return getArguments().getInt("index", 0);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if (container == null) {// We have different layouts, and in one of them this// fragment's containing frame doesn't exist.  The fragment// may still be created from its saved state, but there is// no reason to try to create its view hierarchy because it// won't be displayed.  Note this is not needed -- we could// just run the code below, where we would create and return// the view hierarchy; it would just never be used.return null;}ScrollView scroller = new ScrollView(getActivity());TextView text = new TextView(getActivity());int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,4, getActivity().getResources().getDisplayMetrics());text.setPadding(padding, padding, padding, padding);scroller.addView(text);text.setText(Shakespeare.DIALOGUE[getShownIndex()]);return scroller;}}}
View Code

 

转载于:https://www.cnblogs.com/cubika/p/3177782.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/474214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Kaggle] Heart Disease Prediction

文章目录1. 数据探索2. 特征处理管道3. 训练模型4. 预测kaggle项目地址1. 数据探索 import pandas as pd train pd.read_csv(./train.csv) test pd.read_csv(./test.csv)train.info() test.info() abs(train.corr()[target]).sort_values(ascendingFalse)<class pandas.c…

01.神经网络和深度学习 W2.神经网络基础

文章目录1. 二分类2. 逻辑回归3. 逻辑回归损失函数4. 梯度下降5. 导数6. 计算图导数计算7. 逻辑回归中的梯度下降8. m个样本的梯度下降9. 向量化10. 向量化的更多例子11. 向量化 logistic 回归12. 向量化 logistic 回归梯度输出13. numpy 广播机制14. 关于 python / numpy 向量…

Oracle数据库物理存储结构管理遇到的问题与解决

问题一&#xff1a;当我创建一个重做日志文件放入重做日志文件组中的时候&#xff0c;查询数据字典发现新创建的重做日志文件的状态为“不合法”。 解决方案&#xff1a; 通过查阅相关资料了解到 新建的重做日志文件组成员状态为INVALID,这是由于新建的成员文件还没有被…

01.神经网络和深度学习 W3.浅层神经网络

文章目录1. 神经网络概览2. 神经网络的表示3. 神经网络的输出4. 多样本向量化5. 激活函数6. 为什么需要 非线性激活函数7. 激活函数的导数8. 随机初始化作业参考&#xff1a; 吴恩达视频课 深度学习笔记 1. 神经网络概览 xW[1]b[1]}⟹z[1]W[1]xb[1]⟹a[1]σ(z[1])\left.\begin…

01.神经网络和深度学习 W2.神经网络基础(作业:逻辑回归 图片识别)

文章目录编程题 11. numpy 基本函数1.1 编写 sigmoid 函数1.2 编写 sigmoid 函数的导数1.3 reshape操作1.4 标准化1.5 广播机制2. 向量化2.1 L1\L2损失函数编程题 2. 图片&#x1f431;识别1. 导入包2. 数据预览3. 算法的一般结构4. 建立算法4.1 辅助函数4.2 初始化参数4.3 前向…

PL/SQL程序设计以及安全管理实验遇到的问题及解决

问题一&#xff1a;当我书写PL/SQL语句调用所创建的函数时&#xff0c;报“此范围不存在名为XXX函数名”的错误。 解决&#xff1a; 我通过查阅相关资料&#xff0c;了解到&#xff1a;这种情况主要是调用的函数的参数或者函数名书写错误&#xff0c; 然而&#xff0c;我经过仔…

PowerDesigner使用教程 —— 概念数据模型 (转)

一、概念数据模型概述 概念数据模型也称信息模型&#xff0c;它以实体&#xff0d;联系(Entity-RelationShip,简称E-R)理论为基础&#xff0c;并对这一理论进行了扩充。它从用户的观点出发对信息进行建模&#xff0c;主要用于数据库的概念级设计。 通常人们先将现实世界抽…

阿里云 超级码力在线编程大赛初赛 第1场(第245名)

文章目录1. 比赛结果2. 题目1. 树木规划2. 正三角形拼接3. 大楼间穿梭4. 对称前后缀1. 比赛结果 通过了 3 题&#xff0c;第245名&#xff0c;进入复赛了&#xff0c;收获 T恤 一件&#xff0c;哈哈。 2. 题目 1. 树木规划 题目链接 描述 在一条直的马路上&#xff0c;…

01.神经网络和深度学习 W3.浅层神经网络(作业:带一个隐藏层的神经网络)

文章目录1. 导入包2. 预览数据3. 逻辑回归4. 神经网络4.1 定义神经网络结构4.2 初始化模型参数4.3 循环4.3.1 前向传播4.3.2 计算损失4.3.3 后向传播4.3.4 梯度下降4.4 组建Model4.5 预测4.6 调节隐藏层单元个数4.7 更改激活函数4.8 更改学习率4.9 其他数据集下的表现选择题测试…

[编程启蒙游戏] 2. 奇偶数

文章目录1. 游戏前提2. 游戏目的3. python代码1. 游戏前提 孩子知道奇偶数是什么&#xff0c;不知道也没关系 还可以采用掰手指演示&#xff0c;伸出两个手指能配对&#xff0c;所有伸出来的手指都两两配对了&#xff0c;伸出来的手指个数就是偶数如果还有1个没有找到朋友的手…

过压保护(1)

征一个简单、可靠的电源过压保护电路 http://www.amobbs.com/thread-5542005-1-1.html 防过压&#xff1a;过压之后TVS导通&#xff0c;电流由正极流经自恢复保险再流经TVS到负极&#xff0c;自恢复保险升温&#xff0c;阻值变大&#xff0c;相当于断开&#xff0c;等电流撤去&…

spring boot+thmyleaf ModelAndView页面传值

如上图所示&#xff0c;当我们从后台通过ModelAndView进行传值的时候&#xff0c; 一定要注意&#xff0c;千万不要向上图那样开头加上反斜杠&#xff0c;开头加反斜杠&#xff0c;系统会默认为相对路径&#xff0c; 虽然也能找到相应的视图&#xff08;html&#xff09;&#…

LeetCode 214. 最短回文串(字符串哈希)

文章目录1. 题目2. 解题1. 题目 给定一个字符串 s&#xff0c;你可以通过在字符串前面添加字符将其转换为回文串。 找到并返回可以用这种方式转换的最短回文串。 示例 1: 输入: "aacecaaa" 输出: "aaacecaaa"示例 2: 输入: "abcd" 输出: "…

转:c#委托事件实现窗体传值通信

C#实现Winform窗口间数据交互的三种方法介绍 2010-03-15 来自&#xff1a;CNBLOG 字体大小&#xff1a;【大 中 小】摘要&#xff1a;本文分别介绍C#实现Winform窗口间数据交互的三种方法&#xff1a;修改子窗体的构造函数、给窗体添加属性或方法、通过委托的方法&#xff0c…

LeetCode 1566. 重复至少 K 次且长度为 M 的模式

文章目录1. 题目2. 解题1. 题目 给你一个正整数数组 arr&#xff0c;请你找出一个长度为 m 且在数组中至少重复 k 次的模式。 模式 是由一个或多个值组成的子数组&#xff08;连续的子序列&#xff09;&#xff0c;连续 重复多次但 不重叠 。 模式由其长度和重复次数定义。 …

R语言的安装与配置

一、什么是 R 语言 R 编程语言被广泛应用在统计科学和商业领域。 在各种编程语言排名中 R 语言的排名都很靠前。 它是一款集成了数据操作、统计&#xff0c;以及可视化功能的优秀开源软件。免费&#xff0c;开源是 R 重要的特点。 二、什么是 RStudio RStudio 是用亍 R 编程的…

R语言第一讲

一、R语言入门推荐 推荐四本材料书&#xff1a;R CookBook &#xff1a;hhtp&#xff1a;//www.cookbook-r.com/R in Action http://www.amazon.com/R-Action-Robert-Kabaccoff/dp/1935182390Ggplot2:Elegant Graphics for Data Analysis(User R):hhtp://www.amazon.com/ggplo…

LeetCode 1567. 乘积为正数的最长子数组长度

文章目录1. 题目2. 解题1. 题目 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数组的长度。 一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。 请你返回乘积为正数的最长子数组长度。 示例 1&#xff1a; 输入&#xff1a;nums [1,-2,-…

LeetCode 1568. 使陆地分离的最少天数(DFS)

文章目录1. 题目2. 解题1. 题目 给你一个由若干 0 和 1 组成的二维网格 grid &#xff0c;其中 0 表示水&#xff0c;而 1 表示陆地。 岛屿由水平方向或竖直方向上相邻的 1 &#xff08;陆地&#xff09;连接形成。 如果 恰好只有一座岛屿 &#xff0c;则认为陆地是 连通的 &…