在学过了碎片(Fragment)、ListView之后,实现一个自适应手机和平板的文章阅读应用
效果图:
手机:
平板:
二、实现过程:
1、新建一个文章实体类Newspublic class News {
private String title;
private String content;
public News(String title, String content) {
this.title = title;
this.content = 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;
}
}
包含标题和内容;
2、接着新建一个news_item.xml布局,用于作为文章列表中子项的布局:<?xml version="1.0" encoding="utf-8"?>
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
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"
/>
android:singleLine设置为true表示让这个TextView只能单行显示。android:ellipsize用于设定当文本内容超出控件宽度时,文本的缩略方式,这里指定成end表示在尾部进行缩略。
3、接下来需要创建文章列表的适配器,让这个适配器继承自ArrayAdapter,并将泛型指定为News类package com.csii.www.fragmentnews.adapter;
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.csii.www.fragmentnews.R;
import com.csii.www.fragmentnews.entity.News;
import java.util.List;
/**
* Created by zhang on 2018/3/27.
*/
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);
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;
}
}
可以看到,在getView()方法中,我们获取到了相应位置上的News类,并让文章的标题在列表中进行显示。
4、这样基本就把文章列表部分的代码编写完了,接下来我们看一下如何编写新闻内容部分的代码。新建布局文件的代码。新建布局文件 frag_news_content.xml,代码如下所示:<?xml version="1.0" encoding="utf-8"?>
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_width="1dp"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/spilt_line_vertical"
/>
android:id="@+id/visibility_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
android:orientation="vertical">
android:id="@+id/newsContentTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textSize="20sp" />
android:layout_width="match_parent"
android:layout_height="1dp"
android:scaleType="fitXY"
android:src="@drawable/spilt_line"
/>
android:id="@+id/newsContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="15dp"
android:textSize="18sp"
/>
文章内容的布局主要可以分为两个部分,头部显示完整的文章标题,正文部分显示文章内容,中间使用一条细线分隔开。这里的细线是利用ImageView显示了一张很窄的图片来实现的,将ImageView的android:scaleType属性设置为fitXY,表示让这张图片填充满整个控件的大小。另外外部用了ScrollView布局,支持文章内容较长是可以滚动阅读。
5、然后再新建一个NewsContentFragment类,继承自Fragment,代码如下所示:public class NewsContentFragment extends Fragment{
private View view;
//创建Fragment时候构建一个View
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.frag_news_content,container);
return view;
}
//渲染frament视图view
public void regresh(News news){
//点击文章的时候页面ScrollView滚动到顶部,否则页面在底部,影响体验
view.scrollTo(0,0);
//设置视图的属性显示
View visibilityLayout = view.findViewById(R.id.visibility_layout);
visibilityLayout.setVisibility(View.VISIBLE);
//通过传送过来的News实例,填充内容。
TextView newsTitle = view.findViewById(R.id.newsContentTitle);
TextView newsContent = view.findViewById(R.id.newsContent);
newsTitle.setText(news.getTitle());
newsContent.setText(news.getContent());
}
}
6、接下来还需要再创建一个用于显示新闻列表的布局,新建news_title_frag.xml,代码如下所示:<?xml version="1.0" encoding="utf-8"?>
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/newList"
android:layout_width="match_parent"
android:layout_height="match_parent">
里面只有一个ListView。不过想必你已经猜到了,这个布局并不是给活动使用的,而是给碎片使用的,因此我们还需要创建一个碎片来加载这个布局。新建一个NewsListFragment类,继承自Fragment,代码如下所示: public class NewListFragment extends Fragment implements AdapterView.OnItemClickListener{TitleAdapter titleAdapter;
List newsList = new ArrayList();
boolean isTwoPanel;
//当Fragment和Activity建立联系的时候初始化数据
@Override
public void onAttach(Context context) {
super.onAttach(context);
initNews();//初始化新闻数据
titleAdapter = new TitleAdapter(context, R.layout.news_item, newsList);
}
//创建Fragment时候构建一个View
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag_news_list, container, false);//这里是资源文件的名称
ListView titleList = view.findViewById(R.id.newList);
titleList.setAdapter(titleAdapter);
titleList.setOnItemClickListener(this);
return view;
}
//在活动与页面关联好后,判断是手机还是pad
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(getActivity().findViewById(R.id.news_content_layout) != null ){
isTwoPanel = true;
}else{
isTwoPanel = false;
}
}
private void initNews() {
newsList.add(new News("谁为新词谱一曲",
"林花谢,\n" +
"\n" +
"落尽春红。\n" +
"\n" +
"叹华年易逝,\n" +
"\n" +
"时光太匆匆。\n" +
"\n" +
"无奈人生,山重水复。\n" +
"\n" +
"人生无奈,水复山重。\n" +
"\n" +
"清早间潇潇冷雨,\n" +
"\n" +
"到晚来凄凄寒风。\n" +
"\n" +
"红颜一去,\n" +
"\n" +
"只留下,\n" +
"\n" +
"醉眼中摇曳的倩影;\n" +
"\n" +
"江山倾倒,\n" +
"\n" +
"只留下,\n" +
"\n" +
"心田里胭脂上泪痕。\n" +
"\n" +
"何时入梦里?\n" +
"\n" +
"与君相逢;\n" +
"\n" +
"何时入梦里?\n" +
"\n" +
"与君重逢。\n" +
"\n" +
"怕只怕,\n" +
"\n" +
"人生空余恨,似水东流;\n" +
"\n" +
"怕只怕,\n" +
"\n" +
"人生空余恨,似水长流。"));
newsList.add(new News("国庆节出行", "好急啊"));
}
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
News news = (News)newsList.get(position);
if(isTwoPanel == true ){//双屏显示,点击文章标题刷新右边碎片
//通过getFragmentManager(),然后fundFragmentById()获取页面中的Fragment
NewsContentFragment newContentFragment = (NewsContentFragment)getFragmentManager().findFragmentById(R.id.newContentFragment);
//将New实体传送过去
newContentFragment.regresh(news);
}else{
//如果是手机,直接启动下一个Activity显示文章内容。
NewsContentActivity.startAction(getActivity(),news);
}
}
}
根据碎片的生命周期,我们知道,onAttach()方法会首先执行,因此在这里做了一些数据初始化的操作,比如调用getNews()方法获取几条模拟的文章数据,以及完成NewsAdapter的创建。然后在onCreateView()方法中加载了frag_news_list布局, 并给新闻列表的ListView注册了点击事件。 接下来在onActivityCreated()方法中,我们通过是否能够找到一个id为news_content_layout的View来判断当前是双页模式还是单页模式,这个id为news_content_layout的View只在双页模式中才会出现,在稍后的布局里你将会看到。然后在ListView的点击事件里我们就可以判断,如果当前是单页模式,就启动一个新的活动去显示新闻内容,如果当前是双页模式,就更新文章内容碎片里的数据。
7、修改activity_main.xml中的代码<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="com.csii.www.newsfragment.MainActivity">
android:id="@+id/newListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.csii.www.newsfragment.fragment.NewListFragment"
>
上述代码表示, 在单页模式下, 只会加载一个新闻标题的碎片 。然后新建layout-sw600dp文件夹,在这个文件夹下再新建一个activity_main.xml文件,代码如下所示:<?xml version="1.0" encoding="utf-8"?>
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="com.csii.www.newsfragment.MainActivity">
android:id="@+id/newListFragment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:name="com.csii.www.newsfragment.fragment.NewListFragment"
>
android:id="@+id/news_content_layout"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent">
android:id="@+id/newContentFragment"
android:name="com.csii.www.newsfragment.fragment.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了一个FrameLayout布局下,而这个布局的id正是news_content_layout。因此,能够找到这个id的时候就是双页模式,否则就是单面模式。
8、然后新建NewsContentActivity,作为显示新闻内容的活动,代码如下所示:package com.csii.www.newsfragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import com.csii.www.newsfragment.entity.News;
public class NewsContentActivity extends AppCompatActivity {
public static void startAction(Context context, News news){
Intent intent = new Intent(context,NewsContentActivity.class);
intent.putExtra("newsTitle",news.getTitle());
intent.putExtra("newsContent",news.getContent());
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_content);
Intent intent = getIntent();
String newsTitle = intent.getStringExtra("newsTitle");
String newsContent = intent.getStringExtra("newsContent");
TextView newsTitleView =(TextView) findViewById(R.id.newsContentTitle);
TextView newsContentView =(TextView) findViewById(R.id.newsContent);
newsTitleView.setText(newsTitle);
newsContentView.setText(newsContent);
}
}
对应布局文件:<?xml version="1.0" encoding="utf-8"?>
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.csii.www.newsfragment.NewsContentActivity">
android:id="@+id/newsContentTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textSize="20sp" />
android:layout_width="match_parent"
android:layout_height="1dp"
android:scaleType="fitXY"
android:background="#000"
/>
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1">
android:id="@+id/newsContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="15dp"
android:layout_weight="1"
android:textSize="18sp"
/>
这里只对文章展示部分滑动,标题置顶显示。