【第一行代码】Android中的fragment
2016-03-06 23:49
549 查看
android中的fragment
一、fragment简介
Android自3.0版本开始引入了fragment的概念,它可以让界面在平板上更好地展示。fragment是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。
二、fragment使用方式
包:android.app.Fragment(Android 4.0以上)
类:
1.普通添加fragment
主布局中:
2.动态添加fragment
主布局中:
MainActivity中:
按钮点击事件:
三、fragment和activity之间通信
1.活动中调用fragment中的方法:
调用FragmentManager的findFragmentById()方法,可以在活动中得到相应fragment的实例,然后就能轻松地调用fragment里的方法了。
2.fragment调用活动中的方法:
调用getActivity()方法来得到和当前fragment相关联的活动实例。要使用Context对象也可用。
3.fragment和fragment通信:
首先在一个fragment中可以得到与它相关联的活动,然后再通过这个活动去获取另外一个fragment的实例。
四、fragment的生命周期
1.fragment的状态
a. 运行状态
当一个fragment是可见的,并且它所关联的活动正处于运行状态时,该fragment也处于运行状态。
b. 暂停状态
当一个活动进入暂停状态时(由于另一个未占满屏幕的活动被添加到了栈顶),与它相关联的可见fragment就会进入到暂停状态。
c. 停止状态
当一个活动进入停止状态时,与它相关联的fragment就会进入到停止状态。或者通过调用FragmentTransaction的remove()、replace()方法将fragment从活动中移除,但有在事务提交之前调用addToBackStack()方法,这时的fragment也会进入到停止状态。总的来说,进入停止状态的
d. 销毁状态
fragment总是依附于活动而存在的,因此当活动被销毁时,与它相关联的fragment就会进入到销毁状态。或者通过调用FragmentTransaction的remove()、replace()方法将fragment从活动中移除,但在事务提交之前并没有调用addToBackStack()方法,这时的fragment也会进入到销毁状态。
2.fragment的回调方法
活动中有的回调方法,fragment中几乎都有,不过fragment还提供了一些附加的回调方法
a .onAttach()
当fragment和活动建立关联的时候调用。
b. onCreateView()
为fragment创建视图(加载布局)时调用。
c. onActivityCreated()
确保与fragment相关联的活动一定已经创建完毕的时候调用。
d. onDestroyView()
当与fragment关联的视图被移除的时候调用。
e. onDetach()
当fragment和活动解除关联的时候调用。
fragment的完整生命周期如图4-1所示。
图4-1 fragment的完整生命周期图
五、动态加载布局的办法
1.使用限定符
在运行时判断程序该使用双页模式还是单页模式,需要用到限定符。
Android中一些常见的限定符可以参考下表。
使用例子:在res文件夹里创建layout-large文件夹,其中的布局中含有左右两个fragment,在普通的layout文件夹的布局中只含有一个充满父布局的fragment。这样在大屏幕设备上显示的是双页模式,在普通屏幕上显示的单页模式。
2.使用最小宽度限定符(Android 3.2以上)
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载一个布局,屏幕宽度小于这个值的设备就加载另一个布局。
例如:在res目录下新建layout-sw600dp文件夹,当程序运行在屏幕宽度大于600dp的设备上时,会加载layout-sw600dp/ activity_main布局,当程序运行在屏幕宽度小于600dp的设备上时,则仍然加载默认的layout/activity_main布局。
六、fragment的应用----简易新闻APP
整体思路:使用最小宽度限定符区别大屏设备(双页模式)和小屏设备(单页模式),在大屏的布局文件中添加一个包含contentfragment的framelayout。用是否能获得该layout的id来判断是否是大屏。
大屏设备:同时显示titlefragment和contentfragment(初始时为invisible),点击titlefragment中的列表项时刷新contentfragment的标题和内容。
小屏设备:先显示titlefragment,点击列表项时启动contentactivity,显示对应的布局。
以下是源代码:
MainActivity.java:
NewsContentActivity.java:
NewsAdapter.java:
News:
NewsContentFragment.java:
NewsTitleFragment.java:
布局文件:
layout-sw600dp:
activity_main.xml:
layout
activity_main.xml:
news_content_frag.xml:
news_content.xml:
news_item.xml:
news_title_frag.xml:
实现效果:
平板上:
手机上:
一、fragment简介
Android自3.0版本开始引入了fragment的概念,它可以让界面在平板上更好地展示。fragment是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。
二、fragment使用方式
包:android.app.Fragment(Android 4.0以上)
类:
public class LeftFragment extends Fragment { @Override //动态加载布局 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.left_fragment, container, false); return view; } }
1.普通添加fragment
主布局中:
<fragment android:id="@+id/right_fragment" //显示指明fragment的类名(不能省略包名) android:name="com.example.fragmenttest.RightFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" />
2.动态添加fragment
主布局中:
<FrameLayout android:id="@+id/right_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" > <fragment android:id="@+id/right_fragment" android:name="com.example.fragmenttest.RightFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
MainActivity中:
按钮点击事件:
//创建待获取的fragment实例 AnotherRightFragment fragment = new AnotherRightFragment(); //在活动中获取FragmentManager FragmentManager fragmentManager = getFragmentManager(); //通过beginTransaction()开启一个事务transaction FragmentTransaction transaction = fragmentManager. beginTransaction(); //利用replace()方法向容器中加入fragment,需要传入容器的id和fragment实例 transaction.replace(R.id.right_layout, fragment); //将一个事务添加到返回栈中 transaction.addToBackStack(null); //提交事务 transaction.commit();
三、fragment和activity之间通信
1.活动中调用fragment中的方法:
调用FragmentManager的findFragmentById()方法,可以在活动中得到相应fragment的实例,然后就能轻松地调用fragment里的方法了。
RightFragment rightFragment = (RightFragment) getFragmentManager() .findFragmentById(R.id.right_fragment);
2.fragment调用活动中的方法:
调用getActivity()方法来得到和当前fragment相关联的活动实例。要使用Context对象也可用。
MainActivity activity = (MainActivity) getActivity();
3.fragment和fragment通信:
首先在一个fragment中可以得到与它相关联的活动,然后再通过这个活动去获取另外一个fragment的实例。
四、fragment的生命周期
1.fragment的状态
a. 运行状态
当一个fragment是可见的,并且它所关联的活动正处于运行状态时,该fragment也处于运行状态。
b. 暂停状态
当一个活动进入暂停状态时(由于另一个未占满屏幕的活动被添加到了栈顶),与它相关联的可见fragment就会进入到暂停状态。
c. 停止状态
当一个活动进入停止状态时,与它相关联的fragment就会进入到停止状态。或者通过调用FragmentTransaction的remove()、replace()方法将fragment从活动中移除,但有在事务提交之前调用addToBackStack()方法,这时的fragment也会进入到停止状态。总的来说,进入停止状态的
d. 销毁状态
fragment总是依附于活动而存在的,因此当活动被销毁时,与它相关联的fragment就会进入到销毁状态。或者通过调用FragmentTransaction的remove()、replace()方法将fragment从活动中移除,但在事务提交之前并没有调用addToBackStack()方法,这时的fragment也会进入到销毁状态。
2.fragment的回调方法
活动中有的回调方法,fragment中几乎都有,不过fragment还提供了一些附加的回调方法
a .onAttach()
当fragment和活动建立关联的时候调用。
b. onCreateView()
为fragment创建视图(加载布局)时调用。
c. onActivityCreated()
确保与fragment相关联的活动一定已经创建完毕的时候调用。
d. onDestroyView()
当与fragment关联的视图被移除的时候调用。
e. onDetach()
当fragment和活动解除关联的时候调用。
fragment的完整生命周期如图4-1所示。
图4-1 fragment的完整生命周期图
五、动态加载布局的办法
1.使用限定符
在运行时判断程序该使用双页模式还是单页模式,需要用到限定符。
Android中一些常见的限定符可以参考下表。
屏幕特征 | 限定符 | 描述 |
大 小 | small | 提供给小屏幕设备的资源 |
normal | 提供给中等屏幕设备的资源 | |
large | 提供给大屏幕设备的资源 | |
xlarge | 提供给超大屏幕设备的资源 | |
分 辨 率 | ldpi | 提供给低分辨率设备的资源(120dpi以下) |
mdpi | 提供给中等分辨率设备的资源(120dpi到160dpi) | |
hdpi | 提供给高分辨率设备的资源(160dpi到240dpi) | |
xhdpi | 提供给超高分辨率设备的资源(240dpi到320dpi) | |
方 向 | land | 提供给横屏设备的资源 |
port | 提供给竖屏设备的资源 |
2.使用最小宽度限定符(Android 3.2以上)
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载一个布局,屏幕宽度小于这个值的设备就加载另一个布局。
例如:在res目录下新建layout-sw600dp文件夹,当程序运行在屏幕宽度大于600dp的设备上时,会加载layout-sw600dp/ activity_main布局,当程序运行在屏幕宽度小于600dp的设备上时,则仍然加载默认的layout/activity_main布局。
六、fragment的应用----简易新闻APP
整体思路:使用最小宽度限定符区别大屏设备(双页模式)和小屏设备(单页模式),在大屏的布局文件中添加一个包含contentfragment的framelayout。用是否能获得该layout的id来判断是否是大屏。
大屏设备:同时显示titlefragment和contentfragment(初始时为invisible),点击titlefragment中的列表项时刷新contentfragment的标题和内容。
小屏设备:先显示titlefragment,点击列表项时启动contentactivity,显示对应的布局。
以下是源代码:
MainActivity.java:
package com.linh.news; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.Window; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); } }
NewsContentActivity.java:
package com.linh.news; import com.linh.news.fragments.NewsContentFragment; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.Window; /** * 显示新闻内容的活动 * * @author leroy * */ public class NewsContentActivity extends Activity { //参数代表需要传递的数据,只需要调用该方法即可启动活动 public static void actionStart(Context context, String newsTitle, String newsContent) { Intent intent = new Intent(context, NewsContentActivity.class); intent.putExtra("news_title", newsTitle); intent.putExtra("news_content", newsContent); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.news_content); String newsTitle = getIntent().getStringExtra("news_title");// 获取传入的新闻标题 String newsContent = getIntent().getStringExtra("news_content");// 获取传入的新闻内容 NewsContentFragment newsContentFragment = (NewsContentFragment) getFragmentManager() .findFragmentById(R.id.news_content_fragment); //刷新NewsContentFragment界面 newsContentFragment.refresh(newsTitle, newsContent); } }
NewsAdapter.java:
package com.linh.news.adapter; import java.util.List; //若此处import的是android.R会出错 import com.linh.news.R; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.linh.news.entity.News; /** * 新闻列表适配器 * 获取当前新闻并显示标题 * @author leroy * */ public class NewsAdapter extends ArrayAdapter<News> { private int resourceId; public NewsAdapter(Context context, int textViewResourceId, List<News> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { //获得当前位置上的News类实例 News news = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, null); } else { view = convertView; } TextView newsTitleText = (TextView) view.findViewById(R.id.news_title); //在列表中显示新闻标题 newsTitleText.setText(news.getTitle()); return view; } }
News:
package com.linh.news.entity; /** * 新闻实体类 * 设置和获得新闻的标题和内容 * @author leroy * */ public class News { private String title; private String content; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
NewsContentFragment.java:
package com.linh.news.fragments; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.linh.news.R; /** * 新闻内容fragment * 刷新新闻标题和内容 * @author leroy * */ public class NewsContentFragment extends Fragment { private View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view=inflater.inflate(R.layout.news_content_frag, container,false); return view; } public void refresh(String newsTitle,String newsContent){ View visibilityLayout=view.findViewById(R.id.visibility_layout); visibilityLayout.setVisibility(View.VISIBLE); TextView newsTitleText=(TextView)view.findViewById(R.id.news_title); TextView newsContentText=(TextView)view.findViewById(R.id.news_content); newsTitleText.setText(newsTitle);//刷新新闻标题 newsContentText.setText(newsContent);//刷新新闻内容 } }
NewsTitleFragment.java:
package com.linh.news.fragments; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView; import android.widget.ListView; import com.linh.news.NewsContentActivity; import com.linh.news.R; import com.linh.news.adapter.NewsAdapter; import com.linh.news.entity.News; /** * 显示新闻标题列表的fragment * * @author leroy * */ public class NewsTitleFragment extends Fragment implements OnItemClickListener { private ListView newsTitleListView; private List<News> newsList; private NewsAdapter adapter; private boolean isTwoPane; @Override public void onAttach(Activity activity) { super.onAttach(activity); newsList = getNews();// 初始化新闻数据(模拟数据) adapter = new NewsAdapter(activity, R.layout.news_item, newsList); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater .inflate(R.layout.news_title_frag, container, false); newsTitleListView = (ListView) view .findViewById(R.id.news_title_listview); newsTitleListView.setAdapter(adapter); newsTitleListView.setOnItemClickListener(this); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // 可以找到news_content_layout布局时为双页模式 if (getActivity().findViewById(R.id.news_content_layout) != null) { isTwoPane = true; } else { isTwoPane = false;// 找不到时为单页模式 } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { News news = newsList.get(position); // 如果是双页模式,则刷新NewsContentFragment中的内容 if (isTwoPane) { NewsContentFragment newsContentFragment = (NewsContentFragment) getFragmentManager() .findFragmentById(R.id.news_content_fragment); newsContentFragment.refresh(news.getTitle(), news.getContent()); } else // 如果是单页模式,则直接启动NewsContentActivity来显示新闻内容 { NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent()); } } private List<News> getNews() { List<News> newsList = new ArrayList<News>(); News news1 = new News(); news1.setTitle("人大代表、北大三医院医生:实现分级诊疗,让号贩子自行消失"); news1.setContent("\t2016-03-07 12:03 来自 法治中国。\n“如果能像发达国家那样,大多患者在家门口不同级别的医院都能享受优质医疗水平,患者就不会舍近求远涌向大医院,游离于各大医院的‘号贩子’就失去了生存的土壤,自行消灭。”3月7日上午,十二届全国人大四次会议北京代表团媒体开放日上,全国人大代表、北京大学三医院骨科主任刘忠军在发言时说。"); newsList.add(news1); News news2 = new News(); news2.setTitle("联合国秘书长潘基文年底将卸任,其助理称默克尔为合适继任"); news2.setContent("\t2016-03-07 11:18 来自 澎湃国际。\n中新网3月7日消息,据外媒报道,联合国秘书长潘基文将于年底卸任,继任人选引起各方关注。秘书长人选一直由男性主导,外界要求由女性出任秘书长的呼声日益高涨。负责传讯工作的潘基文助理塞登于《纽约时报》撰文,表示联合国内部有意见认为,应选择在世界舞台上具重要地位的女性继任,德国总理默克尔正是合适人选。"); newsList.add(news2); return newsList; } }
布局文件:
layout-sw600dp:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <!-- 双页模式,同时引入两个fragment,其中内容fragment在framelayout里面,找到即为双页模式 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <fragment android:id="@+id/news_title_fragment" android:name="com.linh.news.fragments.NewsTitleFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <FrameLayout android:id="@+id/news_content_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" > <fragment android:id="@+id/news_content_fragment" android:name="com.linh.news.fragments.NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout> </LinearLayout>
layout
activity_main.xml:
<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" tools:context="com.linh.news.MainActivity" > <!-- 单页模式下只加载一个新闻标题fragment --> <fragment android:id="@+id/news_title_fragment" android:name="com.linh.news.fragments.NewsTitleFragment" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
news_content_frag.xml:
<?xml version="1.0" encoding="utf-8"?> <!--在新闻内容fragment中使用的新闻内容布局 ,标题分割线内容--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/visibility_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:visibility="invisible" > <TextView android:id="@+id/news_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="10dp" android:textSize="20sp" /> <ImageView android:layout_width="match_parent" android:layout_height="10dp" android:scaleType="fitXY" android:src="@drawable/split_line" /> <TextView android:id="@+id/news_content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:padding="15dp" android:textSize="18sp" /> </LinearLayout> <ImageView android:layout_width="10dp" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:scaleType="fitXY" android:src="@drawable/split_line_vertical" /> </RelativeLayout>
news_content.xml:
<?xml version="1.0" encoding="utf-8"?> <!--在活动中使用的新闻内容布局(直接引用新闻内容fragment的布局内容) --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <fragment android:id="@+id/news_content_fragment" android:name="com.linh.news.fragments.NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
news_item.xml:
<?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" > <TextView android:id="@+id/news_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" //超过单行的最末尾以省略号显示 android:paddingBottom="15dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="15dp" android:singleLine="true" //单行模式 android:textSize="18sp" /> </LinearLayout>
news_title_frag.xml:
<?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" > <ListView android:id="@+id/news_title_listview" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
实现效果:
平板上:
手机上:
相关文章推荐
- 《Android开发艺术探索》读书笔记 (5) 第5章 理解RemoteViews
- Android复选框
- Android Transition
- android dp
- Android 应用界面开发笔记
- 关于 android 权重 weight在布局中的理解和使用
- Android Service 复习总结 下
- Android屏幕适配篇(一)
- Android开发60条技术经验总结
- 【Android】TextView中Spannable对象的使用
- android生命周期详解
- android ViewDragHelper详解
- 给初学者的 Android 加密工具
- 《Android开发艺术探索》读书笔记 (4) 第4章 View的工作原理
- 使用Android studio对Android应用签名
- android ViewFlipper实现图片轮播
- 14、 android性能优化总结
- android线程池
- android Bitmap用法总结
- Android自定义ImageView(二)——实现双击放大与缩小图片