您的位置:首页 > 移动开发 > Android开发

【第一行代码】Android中的fragment

2016-03-06 23:49 549 查看
android中的fragment

一、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

提供给竖屏设备的资源

使用例子:在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:

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>

实现效果:

平板上:



手机上:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: