接着上一节我们讲过的Fragment的用法,使用一个APP,为不同屏幕尺寸的设备显示不同的界面(根据屏幕分辨率大小进行分页处理)
使用Fragment做一个新闻的展示。
先明白我们要干什么:
当使用手机进行浏览时,因为手机屏幕分辨率有限,所以决定只支持单页的显示方式。
当使用平板进行浏览时,对于更高的分辨率,选择使用双页的显示方式。(如果是真有钱,还是推荐再搞一个平板版本的吧)
好,知道要干什么,就得定一下我们具体该怎么实现了。
1.有新闻这个类,里边包含俩属性,一个标题,一个内容
2.新建一个news_item.xml布局,用于作为新闻列表子项的布局
3.创建新闻列表的适配器(NewsAdapter),继承自ArrayAdapter,且泛型类为News类
以上基本就是新闻的列表部分,我们还需要看到新闻的内容部分
4.给新闻内容部分写布局文件news_content_frag.xml(在展示时要展示标题以及内容哦)
5.新建一个NewsContentFragment类,继承自Fragment。就是要和刚才创建的布局进行绑定,与此同时,我们还应该在这个类里做些什么事情(一会再说)
我们可以看出来,4、5其实是针对双页面,使用Fragment时所要做的事情。接下来我们做一下单页面的新闻内容显示。
6.创建一个在活动中使用的新闻内容布局 news_content.xml (在单页模式下,我们还是要用Activity的方式进行使用)
7.然后新建NewsContentActivity,作为显示新闻内容的活动,他所要做的活动其实和之前的NewsContentFragment所做的是一样的,所以之后我们会在这里做一个代码的复用~
8.还需要一个用于显示新闻列表的布局,news_title_frag.xml 这个是给碎片用的(这么说可能有所不妥,毕竟是两种展示方式都用到了这个标题的布局,属于两者复用的一个地吧)。
9.创建一个碎片(NewsTitleFragment类)来加载上一个布局。(我们把他作为一个非常重要的文件来编写。)
10.修改一下activit_main.xml的文件内容,用来引入程序的开始
11.新建一个文件夹,叫layout-sw600dp。在其中新建一个activity_main.xml,其中就是两个fragment来进行双页模式的布局显示。
好啦好啦,说了那么多自己都被搞晕了。开始做吧!
1.新闻类
public class News {
private String title;
private String content;
public String getTitle(){
return title;
}
public String getContent(){
return content;
}
public void setTitle(String title){
this.title = title;
}
public void setContent(String content){
this.content = content;
}
}
2.新建一个news_item.xml布局,用于作为新闻列表子项的布局
<
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
:singleLine=
"true"
android
:ellipsize=
"end"
android
:textSize=
"18sp"
android
:paddingLeft=
"10dp"
android
:paddingRight=
"10dp"
android
:paddingTop=
"15dp"
android
:paddingBottom=
"15dp"/>
LinearLayout>
3.创建新闻列表的适配器(NewsAdapter),继承自ArrayAdapter,且泛型类为News类
public class NewsAdapter
extends ArrayAdapter {
private int
resourceId;
public NewsAdapter(Context context,
int textViewResourceId, List objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(
int position, View convertView, ViewGroup parent) {
News news = getItem(position);
if(convertView ==
null){
convertView = LayoutInflater.
from(getContext()).inflate(
resourceId,
null);
}
TextView newsTitleText = (TextView) convertView.findViewById(R.id.
news_title);
newsTitleText.setText(news.getTitle());
return convertView;
}
}
这样就可以获取得到新闻标题的部分了
然后我们需要写一下双页面时右边部分的展示
4.给新闻内容部分写布局文件news_content_frag.xml(在展示时要展示标题以及内容哦)
<
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=
"2dp"
android
:background=
"#f23"
android
:scaleType=
"fitXY" />
<
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=
"2dp"
android
:layout_height=
"match_parent"
android
:background=
"#f23"
android
:scaleType=
"fitXY"/>
RelativeLayout>
5.新建一个NewsContentFragment类,继承自Fragment。就是要和刚才创建的布局进行绑定,与此同时,我们还应该在这个类里做些什么事情。
public class NewsContentFragment
extends Fragment {
private View
view;
@Nullable
@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) visibilityLayout.findViewById(R.id.
news_title);
TextView newsContentText = (TextView) visibilityLayout.findViewById(R.id.
news_content);
newsTitleText.setText(newsTitle);
//刷新新闻的标题
newsContentText.setText(newsContent);
//刷新新闻的内容
}
}
在这个方法中,我们编写了一个refresh的方法用来进行新闻数据的刷新。在此我们就应该进行思考,有关新闻数据内容的展示,不论在单页模式下还是双页模式下,布局是极为相似甚至是一样的,所以在这里我们应该判断关于新闻内容的展示部分应该是可以进行复用的。好,到此为止,我们继续进行。
6.创建一个在活动中使用的新闻内容布局 news_content.xml (在单页模式下,我们还是要用Activity的方式来使用)
<
LinearLayout
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"
android
:orientation=
"vertical">
<
fragment
android
:id=
"@+id/news_content_fragment"
android
:name=
"com.example.yawen_li.fragmentbestpratice.NewsContentFragment"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
tools
:layout=
"@layout/news_content_frag" />
LinearLayout>
7.然后新建NewsContentActivity,作为显示新闻内容的活动,他所要做的活动其实和之前的NewsContentFragment所做的是一样的,所以之后我们会在这里做一个代码的复用~
public class NewsContentActivity
extends AppCompatActivity {
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) {
requestWindowFeature(Window.
FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
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.refresh(newsTitle,newsContent);
//刷新NewsContentFragment界面
}
}
以上两步,就该贯彻了之前我们所讲的代码复用的点了。用Activity来包裹Fragment进行展示,提高了代码的复用率,当然一定要思路清晰,编写好文档,方便以后再回忆时帮助自己记起这些内容。
8.还需要一个用于显示新闻列表的布局,news_title_frag.xml 这个是给碎片用的(两种模式其实是复用了这一个布局)。
<
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_list_view"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent">
ListView>
LinearLayout>
9.创建一个碎片(NewsTitleFragment类)来加载上一个布局。(我们把他作为一个非常重要的文件来编写。)
在这里,我们要进行一些工作,着重讲一下这个类。
1.在这里利用Fragment的生命周期相对Activity靠前的特性,在onAttach()中加载一下数据,new一下adapter
2.在onCreateView()中初始化布局,设置adapter(别忘了设置一下item的点击事件)
3.在onActivityCreated()中对设备屏幕分辨率进行判别(当使用小屏幕手机时,会根据限定符的原因自动屏蔽掉另一个activity_main.xml文件,所以我们只需要查看一下这个文件是否存在即进行了是否使用双页模式)
4.可以在onItemClick()中将双页模式进行分类启动与内容填充。
5.记得写一下新闻数据的初始化。
至此,这个类中要做的事情就已经结束了。看代码部分
public class NewsTitleFragment
extends Fragment
implements AdapterView.OnItemClickListener {
private ListView
newsTitleListView;
private List
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);
}
@Nullable
@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_list_view);
newsTitleListView.setAdapter(
adapter);
newsTitleListView.setOnItemClickListener(
this);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.
news_content_layout) !=
null){
isTwoPane =
true;
//可以找到news_content_layout布局时,为双页模式
}
else {
isTwoPane =
false;
//找不到news_content_layout布局时,为单页模式
}
}
@Override
public void onItemClick(AdapterView> parent, View view,
int position,
long id) {
News news =
newsList.get(position);
if (
isTwoPane){
//如果是双页模式,则刷新NewsContentFragment中的内容
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 getNews(){
List newsList =
new ArrayList();
News news1 =
new News();
news1.setTitle(
"我是News1的新闻标题");
news1.setContent(
"我是News1的新闻主体内容");
newsList.add(news1);
News news2 =
new News();
news2.setTitle(
"我是News2的新闻标题");
news2.setContent(
"我是News2的新闻主体内容");
newsList.add(news2);
return newsList;
}
}
大家在看这段代码的时候要多回去想想我们要做的事情以及事情的经过是怎样的,反复记忆与思考。其实想想也不难,难点就是在执行的顺序上的问题了。
10.修改一下activit_main.xml的文件内容,用来引入程序的开始
<
LinearLayout
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"
android
:paddingLeft=
"@dimen/activity_horizontal_margin"
android
:paddingRight=
"@dimen/activity_horizontal_margin"
android
:paddingTop=
"@dimen/activity_vertical_margin"
android
:paddingBottom=
"@dimen/activity_vertical_margin"
tools
:context=
".MainActivity">
<
fragment
android
:id=
"@+id/news_title_fragment"
android
:name=
"com.example.yawen_li.fragmentbestpratice.NewsTitleFragment"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
tools
:layout=
"@layout/news_item" />
LinearLayout>
11.新建一个文件夹,叫layout-sw600dp。在其中新建一个activity_main.xml,其中就是两个fragment来进行双页模式的布局显示。
<
LinearLayout
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">
<
fragment
android
:id=
"@+id/news_title_fragment"
android
:name=
"com.example.yawen_li.fragmentbestpratice.NewsTitleFragment"
android
:layout_width=
"0dp"
android
:layout_height=
"match_parent"
android
:layout_weight=
"1"
tools
:layout=
"@layout/news_title_frag" />
<
FrameLayout
android
:id=
"@+id/news_content_layout"
android
:layout_width=
"0dp"
android
:layout_height=
"match_parent"
android
:layout_weight=
"1">
<
fragment
android
:id=
"@+id/news_content_fragment"
android
:name=
"com.example.yawen_li.fragmentbestpratice.NewsContentFragment"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
tools
:layout=
"@layout/news_content_frag" />
FrameLayout>
LinearLayout>
在这里我们能很好的看到程序的入口,以及分双页显示的开始是从哪块代码开启的。
回头再看看Fragment的生命周期吧,好好理解Fragment和Activity之间的联系,才能在代码中正确的编写。
真的让我好生思考才明白过来啊。现在想想其实没多难,就是最简单最基本的调用。我们在遇到一个关键点的时候千万回归他的本质,别被眼花缭乱的代码扰乱了自己的思路。脚踏实地才是技术学习唯一的出路呀。