listandroid fragmentt源码在哪

4678人阅读
最近反复研究日常经典必用的几个android app,从主界面带来的交互方式入手进行分析,我将其大致分为三类。今天记录第一种方式,即主界面下面有几个tab页,最上端是标题栏,tab页和tab页之间不是通过滑动切换的,而是通过点击切换tab页。早期这种架构一直是使用tabhost+activitygroup来使用,随着fragment的出现及google官方也大力推荐使用fragment,后者大有代替前者之势。本文也使用fragment进行搭建,标题中的“经典”指这种交互经典,非本文的代码框架结构,欢迎大家提出指出不足,帮助完善。文中的fragment部分参考了郭神的博文(
),代码也是在郭神代码基础上加入了自己对框架的理解。 再次重申下这种主界面交互的特点:1,多个tab,不能滑动切换只能点击切换;2,上有标题栏。这种模式也是目前app中使用最多的。如qq、百度云盘、招商银行、微博、支付宝。几个月前支付宝还是能滑动切换的,后来取消了。视图如下:& & & & & & & &&& & & & & & &下面本文从底部控制栏、顶部控制栏及中间的内容显示载体fragment三部分叙述。一、底部控制栏 底部控制栏里每个控件都不是单一基础控件,上面是图片、下面是文字,右上角是红点,当有更新时红点显示,否则隐藏。另外像qq的右上角还能显示未读消息的个数,我的里是通过大量的layout一点一点搭出来的,这样的好处是方便控制比较直观,另外是可以利用Linearlayout里的layout_weight这个属性,让底部的这些item均匀分布,缺点是代码上有很多重复,维护起来不方便。既然是整理app的通用模板框架,因此我将每个item视为一个对象,然后将其放在底部就ok了。本代码里只封装了上面是图片下面是文字,右上角的红点么有封装进来。ImageText.java就作了这样一件事:package org.yanzi.
import org.yanzi.constant.C
import android.content.C
import android.graphics.C
import android.util.AttributeS
import android.view.LayoutI
import android.view.MotionE
import android.view.V
import android.view.ViewG
import android.widget.ImageV
import android.widget.LinearL
import android.widget.TextV
import com.example.fragmentproject.R;
public class ImageText extends LinearLayout{
private Context mContext =
private ImageView mImageView =
private TextView mTextView =
private final static int DEFAULT_IMAGE_WIDTH = 64;
private final static int DEFAULT_IMAGE_HEIGHT = 64;
private int CHECKED_COLOR = Color.rgb(29, 118, 199); //选中蓝色
private int UNCHECKED_COLOR = Color.GRAY;
//自然灰色
public ImageText(Context context) {
super(context);
// TODO Auto-generated constructor stub
mContext =
public ImageText(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mContext =
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View parentView = inflater.inflate(R.layout.image_text_layout, this, true);
mImageView = (ImageView)findViewById(R.id.image_iamge_text);
mTextView = (TextView)findViewById(R.id.text_iamge_text);
public void setImage(int id){
if(mImageView != null){
mImageView.setImageResource(id);
setImageSize(DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT);
public void setText(String s){
if(mTextView != null){
mTextView.setText(s);
mTextView.setTextColor(UNCHECKED_COLOR);
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
private void setImageSize(int w, int h){
if(mImageView != null){
ViewGroup.LayoutParams params = mImageView.getLayoutParams();
params.width =
params.height =
mImageView.setLayoutParams(params);
public void setChecked(int itemID){
if(mTextView != null){
mTextView.setTextColor(CHECKED_COLOR);
int checkDrawableId = -1;
switch (itemID){
case Constant.BTN_FLAG_MESSAGE:
checkDrawableId = R.drawable.message_
case Constant.BTN_FLAG_CONTACTS:
checkDrawableId = R.drawable.contacts_
case Constant.BTN_FLAG_NEWS:
checkDrawableId = R.drawable.news_
case Constant.BTN_FLAG_SETTING:
checkDrawableId = R.drawable.setting_
if(mImageView != null){
mImageView.setImageResource(checkDrawableId);
对应的布局:&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical& &
&ImageView
android:id=&@+id/image_iamge_text&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_gravity=&center_horizontal& /&
android:id=&@+id/text_iamge_text&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_gravity=&center_horizontal& /&
&/LinearLayout&代码里用到了Constant.java,这里面放的都是常量:package org.yanzi.
public class Constant {
//Btn的标识
public static final int BTN_FLAG_MESSAGE = 0x01;
public static final int BTN_FLAG_CONTACTS = 0x01 && 1;
public static final int BTN_FLAG_NEWS = 0x01 && 2;
public static final int BTN_FLAG_SETTING = 0x01 && 3;
//Fragment的标识
public static final String FRAGMENT_FLAG_MESSAGE = &消息&;
public static final String FRAGMENT_FLAG_CONTACTS = &联系人&;
public static final String FRAGMENT_FLAG_NEWS = &新闻&;
public static final String FRAGMENT_FLAG_SETTING = &设置&;
public static final String FRAGMENT_FLAG_SIMPLE = &simple&;
第一排是复合Button的标识,下面的string类型的是将来创建fragment的标识。完成了ImageText之后,下面就是将4个这样的控件放到一个布局里。为了控制方便,我们将底部栏抽象为一个对象BottomControlPanel.java,这样在维护底部栏相关内容时直接找他就行了。BottomControlPanel继承自RelativeLayout,先来看它的布局:bottom_panel_layout.xml&?xml version=&1.0& encoding=&utf-8&?&
&org.yanzi.ui.BottomControlPanel xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&60dp&
android:layout_alignParentBottom=&true&
android:gravity=&center_vertical&
android:paddingLeft=&20dp&
android:paddingRight=&20dp& &
&org.yanzi.ui.ImageText
android:id=&@+id/btn_message&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_alignParentLeft=&true& /&
&org.yanzi.ui.ImageText
android:id=&@+id/btn_contacts&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_toRightOf=&@id/btn_message& /&
&org.yanzi.ui.ImageText
android:id=&@+id/btn_news&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_toRightOf=&@id/btn_contacts& /&
&org.yanzi.ui.ImageText
android:id=&@+id/btn_setting&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_alignParentRight=&true& /&
&/org.yanzi.ui.BottomControlPanel&对应的java文件:BottomControlPanel.javapackage org.yanzi.
import java.util.ArrayL
import java.util.L
import org.yanzi.constant.C
import android.content.C
import android.graphics.C
import android.util.AttributeS
import android.util.L
import android.view.V
import android.widget.RelativeL
import com.example.fragmentproject.R;
public class BottomControlPanel extends RelativeLayout implements View.OnClickListener {
private Context mC
private ImageText mMsgBtn =
private ImageText mContactsBtn =
private ImageText mNewsBtn =
private ImageText mSettingBtn =
private int DEFALUT_BACKGROUND_COLOR = Color.rgb(243, 243, 243); //Color.rgb(192, 192, 192)
private BottomPanelCallback mBottomCallback =
private List&ImageText& viewList = new ArrayList&ImageText&();
public interface BottomPanelCallback{
public void onBottomPanelClick(int itemId);
public BottomControlPanel(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
protected void onFinishInflate() {
// TODO Auto-generated method stub
mMsgBtn = (ImageText)findViewById(R.id.btn_message);
mContactsBtn = (ImageText)findViewById(R.id.btn_contacts);
mNewsBtn = (ImageText)findViewById(R.id.btn_news);
mSettingBtn = (ImageText)findViewById(R.id.btn_setting);
setBackgroundColor(DEFALUT_BACKGROUND_COLOR);
viewList.add(mMsgBtn);
viewList.add(mContactsBtn);
viewList.add(mNewsBtn);
viewList.add(mSettingBtn);
public void initBottomPanel(){
if(mMsgBtn != null){
mMsgBtn.setImage(R.drawable.message_unselected);
mMsgBtn.setText(&消息&);
if(mContactsBtn != null){
mContactsBtn.setImage(R.drawable.contacts_unselected);
mContactsBtn.setText(&联系人&);
if(mNewsBtn != null){
mNewsBtn.setImage(R.drawable.news_unselected);
mNewsBtn.setText(&新闻&);
if(mSettingBtn != null){
mSettingBtn.setImage(R.drawable.setting_unselected);
mSettingBtn.setText(&设置&);
setBtnListener();
private void setBtnListener(){
int num = this.getChildCount();
for(int i = 0; i & i++){
View v = getChildAt(i);
if(v != null){
v.setOnClickListener(this);
public void setBottomCallback(BottomPanelCallback bottomCallback){
mBottomCallback = bottomC
public void onClick(View v) {
// TODO Auto-generated method stub
initBottomPanel();
int index = -1;
switch(v.getId()){
case R.id.btn_message:
index = Constant.BTN_FLAG_MESSAGE;
mMsgBtn.setChecked(Constant.BTN_FLAG_MESSAGE);
case R.id.btn_contacts:
index = Constant.BTN_FLAG_CONTACTS;
mContactsBtn.setChecked(Constant.BTN_FLAG_CONTACTS);
case R.id.btn_news:
index = Constant.BTN_FLAG_NEWS;
mNewsBtn.setChecked(Constant.BTN_FLAG_NEWS);
case R.id.btn_setting:
index = Constant.BTN_FLAG_SETTING;
mSettingBtn.setChecked(Constant.BTN_FLAG_SETTING);
if(mBottomCallback != null){
mBottomCallback.onBottomPanelClick(index);
public void defaultBtnChecked(){
if(mMsgBtn != null){
mMsgBtn.setChecked(Constant.BTN_FLAG_MESSAGE);
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
layoutItems(left, top, right, bottom);
/**最左边和最右边的view由母布局的padding进行控制位置。这里需对第2、3个view的位置重新设置
* @param left
* @param top
* @param right
* @param bottom
private void layoutItems(int left, int top, int right, int bottom){
int n = getChildCount();
if(n == 0){
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
Log.i(&yanguoqi&, &paddingLeft = & + paddingLeft + & paddingRight = & + paddingRight);
int width = right -
int height = bottom -
Log.i(&yanguoqi&, &width = & + width + & height = & + height);
int allViewWidth = 0;
for(int i = 0; i& i++){
View v = getChildAt(i);
Log.i(&yanguoqi&, &v.getWidth() = & + v.getWidth());
allViewWidth += v.getWidth();
int blankWidth = (width - allViewWidth - paddingLeft - paddingRight) / (n - 1);
Log.i(&yanguoqi&, &blankV = & + blankWidth );
LayoutParams params1 = (LayoutParams) viewList.get(1).getLayoutParams();
params1.leftMargin = blankW
viewList.get(1).setLayoutParams(params1);
LayoutParams params2 = (LayoutParams) viewList.get(2).getLayoutParams();
params2.leftMargin = blankW
viewList.get(2).setLayoutParams(params2);
在onFinishInflate()函数里实例化里面的子元素,在initBottomPanel()里设置每个孩子的图片和文字、监听.onLayout()里对中间的2个孩子的位置进行调整,使其均匀分布,见我的。这个BottomControlPanel实现了View.OnClickListener接口,在onClick()里通过id来判断用户点击了哪一个孩子。判断出来后需要做两件事,一是对这个被点击的对象进行处理,如字体颜色、图片资源的变化,右上角小红点的隐藏等等。另一方面,BottomControlPanel要告诉将来它的主人,也就是Activity到底是点了哪个,通知Activity去切换fragment。可以看到,activity类似个总控中心,BottomControlPanel管理属于它的ImageText,同时上报Activity。Activity知道消息后再切换fragment,每个fragment都有自己的事务逻辑。 这里定义了 public interface BottomPanelCallback{
public void onBottomPanelClick(int itemId); }这个接口,通过传递Id来通知Activity。defaultBtnChecked()函数是apk初次打开后,默认切换到第一个消息fragment上。 这里有个地方需要注意,就是虽然ImageText和BottomControlPanel都是自定义控件,但两者在方式上是有区别的。在ImageText的构造函数里通过inflater将布局加载进来,它对应的布局是个普通的布局。而BottomControlPanel对应的布局文件里,直接使用了定义的BottomControlPanel,在onFinishInflate函数里实例化孩子View。前者是inflate之后实例化的。在使用ImageText到一个新的母布局时是通过&org.yanzi.ui.ImageText /&这种方式进行的,那么使用BottomControlPanel有何区别,请见下文介绍Activity的布局时。二、顶部控制栏 有了底部控制栏,顶部控制栏就可以如法炮制了。这里先交代几句,虽然Android3.0 后Google推出的有ActionBar来做顶部导航栏,参见郭神的这篇。但我发现,本文最前面贴图的几款应用应该都没有使用ActionBar,因为它不够灵活。ActionBar使用起来什么样,大家看看微信就知道了,那个的顶部控制栏就是ActionBar做的,这个应该没跑。 通过观察,顶部控制栏除了标题居中外,在右上角通常会再放一个按钮。不是ImageView就是TextView,这里我为了方便放的是两个TextView,右侧的按钮效果可以再TextView上弄个背景来实现。HeadControlPanel.javapackage org.yanzi.
import org.yanzi.constant.C
import com.example.fragmentproject.R;
import android.content.C
import android.graphics.C
import android.util.AttributeS
import android.widget.RelativeL
import android.widget.TextV
public class HeadControlPanel extends RelativeLayout {
private Context mC
private TextView mMidleT
private TextView mRightT
private static final float middle_title_size = 20f;
private static final float right_title_size = 17f;
private static final int default_background_color = Color.rgb(23, 124, 202);
public HeadControlPanel(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
protected void onFinishInflate() {
// TODO Auto-generated method stub
mMidleTitle = (TextView)findViewById(R.id.midle_title);
mRightTitle = (TextView)findViewById(R.id.right_title);
setBackgroundColor(default_background_color);
public void initHeadPanel(){
if(mMidleTitle != null){
setMiddleTitle(Constant.FRAGMENT_FLAG_MESSAGE);
public void setMiddleTitle(String s){
mMidleTitle.setText(s);
mMidleTitle.setTextSize(middle_title_size);
布局文件head_panel_layout.xml&?xml version=&1.0& encoding=&utf-8&?&
&org.yanzi.ui.HeadControlPanel xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&50dp&
android:layout_alignParentTop=&true&&
android:id=&@+id/midle_title&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_centerInParent=&true&
android:textColor=&@android:color/white&/&
android:id=&@+id/right_title&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_alignParentRight=&true&
android:textColor=&@android:color/white&/&
&/org.yanzi.ui.HeadControlPanel&
三、总控中心Activity和Fragment 先交代下Fragment的使用大致分两种,一种是将Fragment作为一个View写死在布局中,布局里使用android:name来告诉它对应的是哪个实体Fragment。这种添加fragment的方式不能delete和replace掉。另一种是通过获得activity的fragmentmanager和fragmentTransaction和进行动态的添加。这种方式更加灵活,一般使用此种方法。先看Activity的布局activity_main.xml:&RelativeLayout xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:id=&@+id/root_layout&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
tools:context=&org.yanzi.fragmentproject.MainActivity& &
android:id=&@+id/bottom_layout&
layout=&@layout/bottom_panel_layout& /&
android:layout_width=&match_parent&
android:layout_height=&1dip&
android:layout_above=&@id/bottom_layout&
android:background=&#FFE7E7E7& /&
android:id=&@+id/head_layout&
layout=&@layout/head_panel_layout& /&
android:layout_width=&match_parent&
android:layout_height=&1dip&
android:layout_below=&@id/head_layout&
android:background=&#FFE7E7E7& /&
&FrameLayout
android:id=&@+id/fragment_content&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:layout_below=&@id/head_layout&
android:layout_above=&@id/bottom_layout& &
&/FrameLayout&
&/RelativeLayout& 注意看这里是通过include的方式把刚才自定义的上下panel加过来,而不能直接用&org.yanzi.ui.BottomControlPanel /&这种方式直接加载。当然如果也模仿ImageText的构造方式,也是可以这样用的。关于include方式的使用有几个注意事项,就是最好让它的母布局是RelativeLayout,否则的话很难控制include进来的布局的位置。另外,include布局的位置一定要写在include之前,如底部面板在最底部,android:layout_alignParentBottom=&true&这句话是在bottom_panel_layout.xml里写的,如果写在activity_main.xml里就是无效的,这着实是个蛋疼的问题。再就是include后设置的id会覆盖掉以前的,所以这里只在include的时候设置id。其中的两个View是分割线。整体是按照底部栏、上部栏、中间Fragment的容器来放置的。 在放Fragment的时候需要注意,究竟是否要将顶部控制栏放到各自的fragment里合适还是放到Activity里合适要看具体情况,如果顶部栏里多是显示标题这种功能或少量的点击事件,应该放到Activity里,即顶部栏的事务逻辑和当前fragment的事务逻辑耦合的不是很紧。举个例子,比如微信的顶部栏,不管你处在哪个Tab页(聊天、发现、通讯录),点击顶部栏里的按钮都呈现出同样的内容。但反过来讲,如果顶部栏里的事务逻辑和fragment耦合很紧,即在不同的fragment,顶部栏呈现的内容都不一样,且点击后处理的事务也和当前fragment紧密联系一起,那就应该一个fragment配套一个顶部栏,方便控制。本文是将两者分开的。所以让fragment的容器在顶部栏之下,底部栏之上,不这样写的话,就会遮挡。& & &FrameLayout& & & & android:id=&@+id/fragment_content&& & & & android:layout_width=&match_parent&& & & & android:layout_height=&wrap_content&& & & & android:layout_below=&@id/head_layout&& & & & android:layout_above=&@id/bottom_layout& && & &/FrameLayout&MainActivity.java代码:package org.yanzi.
import org.yanzi.constant.C
import org.yanzi.fragment.BaseF
import org.yanzi.fragment.ContactsF
import org.yanzi.fragment.MessageF
import org.yanzi.fragment.NewsF
import org.yanzi.fragment.SettingF
import org.yanzi.ui.BottomControlP
import org.yanzi.ui.BottomControlPanel.BottomPanelC
import org.yanzi.ui.HeadControlP
import android.app.A
import android.app.F
import android.app.FragmentM
import android.app.FragmentT
import android.os.B
import android.text.TextU
import android.util.L
import android.view.M
import android.widget.T
import com.example.fragmentproject.R;
public class MainActivity extends Activity implements BottomPanelCallback {
BottomControlPanel bottomPanel =
HeadControlPanel headPanel =
private FragmentManager fragmentManager =
private FragmentTransaction fragmentTransaction =
/* private MessageFragment messageF
private ContactsFragment contactsF
private NewsFragment newsF
private SettingFragment settingF*/
public static String currFragTag = &&;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getFragmentManager();
setDefaultFirstFragment(Constant.FRAGMENT_FLAG_MESSAGE);
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
private void initUI(){
bottomPanel = (BottomControlPanel)findViewById(R.id.bottom_layout);
if(bottomPanel != null){
bottomPanel.initBottomPanel();
bottomPanel.setBottomCallback(this);
headPanel = (HeadControlPanel)findViewById(R.id.head_layout);
if(headPanel != null){
headPanel.initHeadPanel();
/* 处理BottomControlPanel的回调
* @see org.yanzi.ui.BottomControlPanel.BottomPanelCallback#onBottomPanelClick(int)
public void onBottomPanelClick(int itemId) {
// TODO Auto-generated method stub
String tag = &&;
if((itemId & Constant.BTN_FLAG_MESSAGE) != 0){
tag = Constant.FRAGMENT_FLAG_MESSAGE;
}else if((itemId & Constant.BTN_FLAG_CONTACTS) != 0){
tag = Constant.FRAGMENT_FLAG_CONTACTS;
}else if((itemId & Constant.BTN_FLAG_NEWS) != 0){
tag = Constant.FRAGMENT_FLAG_NEWS;
}else if((itemId & Constant.BTN_FLAG_SETTING) != 0){
tag = Constant.FRAGMENT_FLAG_SETTING;
setTabSelection(tag); //切换Fragment
headPanel.setMiddleTitle(tag);//切换标题
private void setDefaultFirstFragment(String tag){
Log.i(&yan&, &setDefaultFirstFragment enter... currFragTag = & + currFragTag);
setTabSelection(tag);
bottomPanel.defaultBtnChecked();
Log.i(&yan&, &setDefaultFirstFragment exit...&);
private void commitTransactions(String tag){
if (fragmentTransaction != null && !fragmentTransaction.isEmpty()) {
currFragTag =
fragmentTransaction =
private FragmentTransaction ensureTransaction( ){
if(fragmentTransaction == null){
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
return fragmentT
private void attachFragment(int layout, Fragment f, String tag){
if(f != null){
if(f.isDetached()){
ensureTransaction();
fragmentTransaction.attach(f);
}else if(!f.isAdded()){
ensureTransaction();
fragmentTransaction.add(layout, f, tag);
private Fragment getFragment(String tag){
Fragment f = fragmentManager.findFragmentByTag(tag);
if(f == null){
Toast.makeText(getApplicationContext(), &fragment = null tag = & + tag, Toast.LENGTH_SHORT).show();
f = BaseFragment.newInstance(getApplicationContext(), tag);
private void detachFragment(Fragment f){
if(f != null && !f.isDetached()){
ensureTransaction();
fragmentTransaction.detach(f);
/**切换fragment
* @param tag
void switchFragment(String tag){
if(TextUtils.equals(tag, currFragTag)){
//把上一个fragment detach掉
if(currFragTag != null && !currFragTag.equals(&&)){
detachFragment(getFragment(currFragTag));
attachFragment(R.id.fragment_content, getFragment(tag), tag);
commitTransactions( tag);
/**设置选中的Tag
* @param tag
void setTabSelection(String tag) {
// 开启一个Fragment事务
fragmentTransaction = fragmentManager.beginTransaction();
if(TextUtils.equals(tag, Constant.FRAGMENT_FLAG_MESSAGE)){
if (messageFragment == null) {
messageFragment = new MessageFragment();
}else if(TextUtils.equals(tag, Constant.FRAGMENT_FLAG_CONTACTS)){
if (contactsFragment == null) {
contactsFragment = new ContactsFragment();
}else if(TextUtils.equals(tag, Constant.FRAGMENT_FLAG_NEWS)){
if (newsFragment == null) {
newsFragment = new NewsFragment();
}else if(TextUtils.equals(tag,Constant.FRAGMENT_FLAG_SETTING)){
if (settingFragment == null) {
settingFragment = new SettingFragment();
}else if(TextUtils.equals(tag, Constant.FRAGMENT_FLAG_SIMPLE)){
if (simpleFragment == null) {
simpleFragment = new SimpleFragment();
switchFragment(tag);
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
currFragTag = &&;
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
注意这块我作了改动,不需要申明/* private MessageFragment messageF private ContactsFragment contactsF private NewsFragment newsF private SettingFragment settingF*/这些内容,因为Fragment的生成是通过BaseFragment.newInstance()来生成的,传进去Tag生成相应的Fragment。所有的Fragment,ContactsFragment、MessageFragment、NewsFragment、SettingFragment都继承自BaseFragment,通过BaseFragment里的newInstance()接口进行实例化对应的fragment。优点是方便管理,缺点么也有,因为java继承继承一个类,不能同时继承两个类。所以如ListFragment这些,就没法同时继承了。不过好在有listview这些,也妨碍不了我们做到同样的效果。 Activity里事件的入口是在onBottomPanelClick()监听点击了谁,然后:setTabSelection(tag); //切换FragmentheadPanel.setMiddleTitle(tag);//切换标题& 先切换Fragment再切换顶部栏的标题。setTabSelection()里直接调switchFragment(),在switchFragment函数里先判断标签是否一样,一样则意外着无需切换,否则的话就先把当前Fragment找到然后detach掉,之后进到attachFragment()函数里。在这里,先判断这个fragment是不是被detach掉的,如果是的话意味着之前曾被add过,所以只需attach就ok了。否则的话,意味着这是第一次,进行add.这里记录下Fragment的声明周期: MessageFragment正常打开: Line 155: 01-04 11:50:46.688 E/MessageFragment( 2546): onAttach----- Line 159: 01-04 11:50:46.688 E/MessageFragment( 2546): onCreate------ Line 161: 01-04 11:50:46.693 D/MessageFragment( 2546): onCreateView----& Line 165: 01-04 11:50:46.694 E/MessageFragment( 2546): onActivityCreated------- Line 169: 01-04 11:50:46.694 E/MessageFragment( 2546): onStart-----& Line 173: 01-04 11:50:46.694 E/MessageFragment( 2546): onresume----& 返回键退出: Line 183: 01-04 11:52:26.506 E/MessageFragment( 2546): onpause Line 259: 01-04 11:52:27.131 E/MessageFragment( 2546): onStop Line 263: 01-04 11:52:27.132 E/MessageFragment( 2546): ondestoryView Line 269: 01-04 11:52:27.134 E/MessageFragment( 2546): ondestory Line 271: 01-04 11:52:27.135 D/MessageFragment( 2546): onDetach------
按home按键退出: Line 97: 01-05 05:06:15.659 E/MessageFragment(18835): onpause Line 215: 01-05 05:06:16.292 E/MessageFragment(18835): onStop 再次打开: Line 81: 01-05 05:07:02.408 E/MessageFragment(18835): onStart-----& Line 85: 01-05 05:07:02.408 E/MessageFragment(18835): onresume----&
通过detach的方式切换至其他Fragment: Line 69: 01-04 11:53:33.381 E/MessageFragment( 2546): onpause Line 73: 01-04 11:53:33.382 E/MessageFragment( 2546): onStop Line 77: 01-04 11:53:33.382 E/MessageFragment( 2546): ondestoryView 再次切换过来: Line 55: 01-04 11:54:59.462 D/MessageFragment( 2546): onCreateView----& Line 59: 01-04 11:54:59.463 E/MessageFragment( 2546): onActivityCreated------- Line 63: 01-04 11:54:59.463 E/MessageFragment( 2546): onStart-----& Line 67: 01-04 11:54:59.464 E/MessageFragment( 2546): onresume----&四、适配器和MessageBean 本来要连数据库的,时间原因用个简单的MessageBean代替了。一个消息分联系人头像、名字、消息正文和时间四部分组成,封装到一个MessageBean里。MessageBean.javapackage org.yanzi.
public class MessageBean {
private int PhotoDrawableId;
private String MessageN
private String MessageC
private String MessageT
public MessageBean(){
public MessageBean(int photoDrawableId, String messageName,
String messageContent, String messageTime) {
PhotoDrawableId = photoDrawableId;
MessageName = messageN
MessageContent = messageC
MessageTime = messageT
public int getPhotoDrawableId() {
return PhotoDrawableId;
public void setPhotoDrawableId(int mPhotoDrawableId) {
this.PhotoDrawableId = mPhotoDrawableId;
public String getMessageName() {
return MessageN
public void setMessageName(String messageName) {
MessageName = messageN
public String getMessageContent() {
return MessageC
public void setMessageContent(String messageContent) {
MessageContent = messageC
public String getMessageTime() {
return MessageT
public void setMessageTime(String messageTime) {
MessageTime = messageT
public String toString() {
return &MessageBean [mPhotoDrawableId=& + PhotoDrawableId
+ &, MessageName=& + MessageName + &, MessageContent=&
+ MessageContent + &, MessageTime=& + MessageTime + &]&;
然后就是MessageFragment的ListView里的适配器,MessageAdapter.javapackage org.yanzi.fragment.
import java.util.L
import org.yanzi.bean.MessageB
import com.example.fragmentproject.R;
import android.content.C
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import android.widget.BaseA
import android.widget.ImageV
import android.widget.TextV
public class MessageAdapter extends BaseAdapter {
private List&MessageBean& mListMsgBean =
private Context mC
private LayoutInflater mI
public MessageAdapter(List&MessageBean& listMsgBean, Context context){
mListMsgBean = listMsgB
mContext =
mInflater = LayoutInflater.from(mContext);
public int getCount() {
// TODO Auto-generated method stub
return mListMsgBean.size();
public Object getItem(int position) {
// TODO Auto-generated method stub
return mListMsgBean.get(position);
public long getItemId(int position) {
// TODO Auto-generated method stub
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = mInflater.inflate(R.layout.message_item_layout, null);
ImageView imageView = (ImageView) v.findViewById(R.id.img_msg_item);
imageView.setImageResource(mListMsgBean.get(position).getPhotoDrawableId());
TextView nameMsg = (TextView)v.findViewById(R.id.name_msg_item);
nameMsg.setText(mListMsgBean.get(position).getMessageName());
TextView contentMsg = (TextView)v.findViewById(R.id.content_msg_item);
contentMsg.setText(mListMsgBean.get(position).getMessageContent());
TextView timeMsg = (TextView)v.findViewById(R.id.time_msg_item);
timeMsg.setText(mListMsgBean.get(position).getMessageTime());
因为是示例,getView里没用ViewHolder。最后是MessageFragment里通过对listview设置适配器,将MessageBean作为信息的提供者也填充到适配器里。MessageFragment.java代码:package org.yanzi.
import java.util.ArrayL
import java.util.L
import org.yanzi.activity.MainA
import org.yanzi.bean.MessageB
import org.yanzi.constant.C
import org.yanzi.fragment.adapter.MessageA
import android.app.A
import android.os.B
import android.util.L
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import android.widget.AdapterV
import android.widget.T
import android.widget.AdapterView.OnItemClickL
import android.widget.ListV
import com.example.fragmentproject.R;
public class MessageFragment extends BaseFragment {
private static final String TAG = &MessageFragment&;
private MainActivity mMainA
private ListView mListV
private MessageAdapter mMsgA
private List&MessageBean& mMsgBean = new ArrayList&MessageBean&();
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View messageLayout = inflater.inflate(R.layout.message_layout,
container, false);
Log.d(TAG, &onCreateView----&&);
mMainActivity = (MainActivity) getActivity();
mFragmentManager = getActivity().getFragmentManager();
mListView = (ListView)messageLayout.findViewById(R.id.listview_message);
mMsgAdapter = new MessageAdapter(mMsgBean, mMainActivity);
mListView.setAdapter(mMsgAdapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView&?& parent, View view,
int position, long id) {
// TODO Auto-generated method stub
Toast.makeText(mMainActivity, mMsgBean.get(position).toString(),
Toast.LENGTH_SHORT).show();
return messageL
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
Log.e(TAG, &onAttach-----&);
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Log.e(TAG, &onCreate------&);
mMsgBean.add(new MessageBean(R.drawable.ic_photo_1, &张三&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_2, &李四&, &哈哈&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_3, &小明&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_4, &王五&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_5, &Jack&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_6, &Jone&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_7, &Jone&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_8, &Jone&, &吃饭没?&, &昨天&));
mMsgBean.add(new MessageBean(R.drawable.ic_photo_9, &Jone&, &吃饭没?&, &昨天&));
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Log.e(TAG, &onActivityCreated-------&);
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e(TAG, &onStart-----&&);
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.e(TAG, &onresume----&&);
MainActivity.currFragTag = Constant.FRAGMENT_FLAG_MESSAGE;
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
Log.e(TAG, &onpause&);
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
Log.e(TAG, &onStop&);
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
Log.e(TAG, &ondestoryView&);
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e(TAG, &ondestory&);
public void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
Log.d(TAG, &onDetach------&);
最后来看下效果吧,只有MessageFragment填充了数据:& & &&横屏情况下:--------------本文系原创,转载请注明作者yanzi1225627
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1062430次
积分:14331
积分:14331
排名:第240名
原创:282篇
转载:12篇
评论:1533条
文章:15篇
阅读:130916
(1)(3)(17)(14)(7)(8)(7)(6)(3)(7)(7)(3)(3)(7)(5)(6)(11)(24)(6)(11)(10)(13)(11)(34)(39)(2)(23)(6)}

我要回帖

更多关于 fragment design 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信