Fragment开发实例

[b]SVN源码下载地址:[/b] https://svn.codespot.com/a/eclipselabs.org/demo1/trunk/myAndroid2_2
或者请下载附件myAndroid2_2.rar.

[b]说明: [/b]
这个实例原本是用ANDROID2.2开发的,因此取了2.2的名字。 现在, 该应用的ANDROID已经提升到4.0.

[b]Fragment的使用[/b]
android应用了一个UI设计理念:一个activity可以包含多个fragment。 比如实例中的国家管理模型, 当进入国家管理时(layout activity), 左边出现已经输入的国家列表(list fragment), 点击列表中的国家名称,右边则出现该国家的具体内容(details fragment)。 以上设计就是典型的 list-details 模式。

这个模式不仅适用于水平展示的屏幕(landscape), 也适用于竖直展示的屏幕(portrait)。 当水平展示时,屏幕左侧是list, 右侧是details; 而竖直展示时,屏幕只显示list, 点击其中的具体内容,屏幕显示details.

[b]实例中的代码解释:[/b]
1. CountryLayout.java 整个国家管理界面。 该界面提供了2个MENU,一个是返回主菜单(back), 另一个是添加菜单(new).

2. CountryListFragment.java 显示了所有的国家列表。

3. CountryDetailsFragment.java 显示了具体的国家内容。该界面提供了几个按钮: 在landscape情况下, 有修改(edit)按钮和删除(delete)按钮, 在portrait情况下,不仅有修改和删除两个按钮,还增加了返回列表(list)的按钮(to previous)

4. CountryDialogFragment.java 显示了国家的操作界面,保存按钮保存(save)添加或修改的内容, 关闭按钮(close)关闭操作界面。

[b]源码要点:[/b]
1. Activity和fragment之间的联系
1) 在fragment中建立接口,并利用fragment的onAttach生命周期建立activity和fragment的联系。

xxxfragment.java
public interface OnHeadlineSelectedListener {
/** Called by HeadlinesFragment when a list item is selected */
public void onArticleSelected(int position, long id);

}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);

// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}


2) 在activity中调用fragment建立的接口,并完成接口的具体实现方法

xxxactivity.java implement xxxFragment.OnHeadlineSelectedListener
@Override
public void onArticleSelected(int position, long id) {

// Capture the article fragment from the activity layout
CountryDetailsFragment articleFrag = (CountryDetailsFragment)
getFragmentManager().findFragmentById(R.id.details);

if (articleFrag != null) {
articleFrag.updateArticleView(id);
} else {
newDetailsFragment(id);
}

}


2. 创建fragment时的要点
1) fragment管理器

// 找到管理器
FragmentTransaction ft = getFragmentManager().beginTransaction();
// 将创建的details fragment替换原来的fragment。
ft.replace(R.id.details, details);
。。。。。。
//提交
ft.commit();


2) 判断fragment是否存在

//通过ID寻找的方法
CountryDetailsFragment details = (CountryDetailsFragment) getFragmentManager().findFragmentById(R.id.details);
// 还有一种是通过Tag来查找的,我这里暂时没有实例。


3) fragment中参数传递

Bundle bundle = new Bundle();
bundle.putLong("selectedId", id);
bundle.putBoolean("mDualPane", mDualPane);
// 将参数邦定fragment.
details.setArguments(bundle);


4) 创建fragment时UI元素的提取

View v = inflater.inflate(R.layout.area_details, container, false);

text1 = (TextView) v.findViewById(R.id.areaName);
text2 = (TextView) v.findViewById(R.id.areaDetails);
......


[b]源码要点的实际应用:[/b]
1. 水平屏幕和竖直屏幕的设置(config landscape and portrait),

为了适应不同屏幕,android配置方法如下:
1) 在 res/values目录下增加layouts.xml(portrait配置), 在 res/values-land目录下也增加layouts.xml(landscape配置).

2) res/values/layouts.xml

<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="country_layout" type="layout">@layout/country_onepane</item>
<bool name="has_two_panes">false</bool>
</resources>


3) res/values-land/layouts.xml

<resources>
<item name="country_layout" type="layout">@layout/country_twopane</item>
<bool name="has_two_panes">true</bool>
</resources>


2. config fragment
2-1) portrait配置: res/layout/country_onepane.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment class="cn.com.demo.android.activity.CountryListFragment"
android:id="@+id/titles"
android:layout_width="match_parent" android:layout_height="match_parent" />

</LinearLayout>


2-2) portrait配置: res/layout-land/country_twopane.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">

<fragment class="cn.com.demo.android.activity.CountryListFragment"
android:id="@+id/titles" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />

<FrameLayout android:id="@+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" />

</LinearLayout>


3. layout activity: CountryLayout.java

1) protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// 根据屏幕判断是调用landscape的xml文件,还是portrait的xml文件。
[i]setContentView(R.layout.country_layout);[/i]

// mIsDualPane是判断屏幕是否为landscape的关键,它将作为一个参数传递给其它fragment.
View detailsFrame = findViewById(R.id.details);
mIsDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

}


2) 需要运行CountryListFragment.OnHeadlineSelectedListener接口方法

public void onArticleSelected(int position, long id) {

// 判断是否存在details fragment, 如果不存在,需要创建 details fragment.
CountryDetailsFragment articleFrag = (CountryDetailsFragment)
getFragmentManager().findFragmentById(R.id.details);

if (articleFrag != null) {
articleFrag.updateArticleView(id);
} else {
newDetailsFragment(id);
}

}


3. list fragment
OnHeadlineSelectedListener mCallback;
1) 定义接口

public interface OnHeadlineSelectedListener {
/** Called by HeadlinesFragment when a list item is selected */
public void onArticleSelected(int position, long id);

}


2) 按照android开发者网站的文档说明,这个onAttach方法是属于fragment的生命周期,用于和调用它的activity联系,以便activity能够调用它的接口。

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);

// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}


3) 当列表中的具体项被点击时,显示details的方法。

@Override
public void onListItemClick(ListView l, View v, int position, long id) {

if(mDualPane){
mCallback.onArticleSelected(position, id);
getListView().setItemChecked(position, true);
}
showDetails(id);
}


4) 显示details内容

void showDetails(long id){
// 如果是landscape 屏幕, 直接显示detailsFragment, 如果是portrait屏幕,这显示detailsActivity.
if (mDualPane) {
// Check what fragment is currently shown, replace if needed.
CountryDetailsFragment details = (CountryDetailsFragment) getFragmentManager().findFragmentById(R.id.details);

if(details==null || id==0){
this.newDetailsFragment(details, id);
}else
details.updateArticleView(id);

}else{
this.newDetailsActivity(id);

}
}


4. details fragment
1) 创建details fragment时, 通过mDualPane判断,是landscape,还是portrait.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

........

mDualPane = getArguments().getBoolean("mDualPane");

if(mDualPane){

// landscape时fragment调用UI组件的方法。
View v = inflater.inflate(R.layout.area_details, container, false);

text1 = (TextView) v.findViewById(R.id.areaName);
text2 = (TextView) v.findViewById(R.id.areaDetails);

previous = (Button) v.findViewById(R.id.country_toprevious);
delete = (Button) v.findViewById(R.id.country_delete);
edit = (Button) v.findViewById(R.id.country_edit);

if(previous!=null) previous.setVisibility(View.GONE);
toggleButtons(View.INVISIBLE);

if(delete!=null) delete.setOnClickListener(deleteMe);
if(edit!=null) edit.setOnClickListener(editMe);

long _id = getArguments().getLong("selectedId");
if(_id>0) this.displayDetails(_id);

return v;

}else{
// portrait时,activity调用UI组件的方法。(同intent调用方法)
getActivity().setContentView(R.layout.area_details);

extras = getActivity().getIntent().getExtras();

previous = (Button) getActivity().findViewById(R.id.country_toprevious);
delete = (Button) getActivity().findViewById(R.id.country_delete);
edit = (Button) getActivity().findViewById(R.id.country_edit);

if(previous!=null) previous.setOnClickListener(previousMe);
if(delete!=null) delete.setOnClickListener(deleteMe);
if(edit!=null) edit.setOnClickListener(editMe);

display();

return null;
}


}


2) 调用dialog fragment的方法

void showDialog(){

FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag(COUNTRY_DIALOG_FRAGMENT);
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);

// Create and show the dialog.
DialogFragment newFragment = CountryDialogFragment.newInstance();
Bundle bundle = new Bundle();
bundle.putLong("selectedId", id);
bundle.putBoolean("mDualPane", mDualPane);

newFragment.setArguments(bundle);
newFragment.show(ft, COUNTRY_DIALOG_FRAGMENT);

}


5. dialog fragment

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// 设置dialog的显示style和theme
int style = DialogFragment.STYLE_NORMAL, theme = android.R.style.Theme_Holo_Light;
setStyle(style, theme);

Bundle args = getArguments();
if(args!=null) id = args.getLong("selectedId");
if(args!=null) mDualPane = args.getBoolean("mDualPane");

Log.i(TAG,"args is null:" + ((args==null)?true:false));

......
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值