在写代码之前想好自己的需求是什么那是非常重要的,需求:1. 分清楚双页模式和单页模式。让项目可以一套代码运行; 2. 单页模式下,有一个新闻列表,点击里面的新闻标题跳转到新闻详情页; 3. 双页模式下,左边是新闻列表,右边是新闻详情,点击左边的新闻列表,右边的新闻详情随之更新。
ok,需求清楚了,下面就开始敲代码吧!
如果大家对碎片的概念不是很理解,欢迎观看我的另一篇博客手机平板要兼顾———探究碎片
创建项目,添加后面需要用到的 RecyclerView 依赖库:
compile 'com.android.support:recyclerview-v7:28.0.0'
新建完项目后,在activity_main里面放一个碎片,作为单页模式的新闻列表 :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="@+id/news_title_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<!--在单页模式下只会加载一个新闻标题的碎片-->
<fragment
android:id="@+id/left_fragment"
android:name="com.djp.administrator.fragmenttest.NewsTitleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
接下来,准备好一个新闻的实体类,新建类 News,代码如下所示:
/**
* 新闻实体类
* Created by KXwon on 2016/12/12.
*/
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;
}
}
接着新建一个 news_content_frag.xml 布局,作为新闻内容的布局:
<?xml version="1.0" encoding="utf-8"?>
<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:text="东营职业学院"
android:textSize="20sp" />
<!--分割线-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000"/>
<!--新闻正文-->
<TextView
android:id="@+id/news_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="18sp"
android:padding="15dp"/>
</LinearLayout>
<!--分割线-->
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#000"/>
</RelativeLayout>
新闻内容的布局主要分为两个部分,头部显示新闻标题,正文显示新闻内容,中间使用一条细线分隔开;
然后再新建一个 NewsContentFragment 类,如下:
/**
* 新闻内容Fragment
*/
public class NewsContentFragment extends Fragment {
private View view;
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);//把visibilityLayout设置成可见
TextView newsTitleText = (TextView) view.findViewById (R.id.news_title);//获取新闻标题控件
TextView newsContentText = (TextView) view.findViewById(R.id.news_content);//获取新闻正文控件
newsTitleText.setText(newsTitle);//刷新新闻标题
newsContentText.setText(newsContent);//刷新新闻内容
}
}
这样就把新闻内容的碎片和布局创建好了
但它们都是在双页模式下使用的,若要在单页模式中使用
还需创建一个活动 NewsContentActivity,其布局 news_content.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
android:id="@+id/news_content_fragment"
android:name="com.djp.administrator.fragmenttest.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
这里直接在布局中引入了 NewsContentFragment,相当于把 news_content_frag 布局的内容自动加了进来,
然后编写 NewsContentActivity 的代码,如下:
/**
* 单页模式
*/
public class NewsContentActivity extends AppCompatActivity {
/**
* 构建Intent,传递所需数据
*/
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);
setContentView(R.layout.news_content);
//获取传入的新闻标题、新闻内容
String newsTitle = getIntent().getStringExtra("news_title");
String newsContent = getIntent().getStringExtra("news_content");
//获取NewsContentFragment 实例
NewsContentFragment newsContentFragment = (NewsContentFragment) getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
//刷新NewsContentFragment 显示数据
newsContentFragment.refresh(newsTitle,newsContent);
}
}
在 onCreate() 方法中通过 Intent 获取传入的新闻标题和内容
然后调用 FragmentManager 的 findFragmentById() 方法得到 NewsContentFragment 的实例
接着调用它的 refresh() 方法,并将新闻的标题和内容传入,显示数据
接下来还需再创建显示新闻列表的布局 news_title_frag.xml,如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--新闻列表-->
<android.support.v7.widget.RecyclerView
android:id="@+id/news_title_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
新建 news_item.xml 作为 上述 RecyclerView 子项的布局:
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
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:padding="10dp"/>
子项的布局就只有一个 TextView
新闻列表和子项布局都创建好了,接下来就需要一个用于展示新闻列表的地方
这里新建 NewsTitleFragment 作为展示新闻列表的碎片:
/**
* 新闻列表fragment
*/
public class NewsTitleFragment extends Fragment{
private boolean isTowPane;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_content_frag, container, false);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.news_content_layout)!= null){
// 可以找到 news_content_layout 布局时,为双页模式
isTowPane = true;
}else {
// 找不到 news_content_layout 布局时,为单页模式
isTowPane = false;
}
}
}
为实现上述 onActivityCreated() 方法中判断当前时双页还是单页模式
接下来在 NewsTitleFragemt 中新建一个内部类 NewsAdapter 来作为 RecyclerView 的适配器
如下:
public class NewsTitleFragment extends Fragment{
private boolean isTowPane;
. . .
/**
* RecyclerViews适配器
* */
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<News> mNewsList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView newsTitleText;
public ViewHolder(View view) {
super(view);
newsTitleText = (TextView) view.findViewById(R.id.news_title);//新闻标题
}
}
public NewsAdapter(List<News> newsList) {
mNewsList = newsList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//加载布局
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
//每个Item的点击事件
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
News news = mNewsList.get(holder.getAdapterPosition());
//如果是双页模式,则刷新NewsContentActivity中的数据
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());
}
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
News news = mNewsList.get(position);
holder.newsTitleText.setText(news.getTitle());
}
@Override
public int getItemCount() {
return mNewsList.size();
}
}
需要注意的是,这里把适配器写成内部类是为了直接访问 NewsTitleFragment 的变量
比如:isTowPane
现在还剩最后一步收尾工作,就是向 RecyclerView 中填充数据了
修改 NewsTitleFragment 中的代码,如下所示:
public class NewsTitleFragment extends Fragment{
. . .
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag, container, false);
//RecyclerView实例
RecyclerView newsTitleRecyclerView = (RecyclerView) view.findViewById(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsTitleRecyclerView.setLayoutManager(layoutManager);//指定布局为线性布局
NewsAdapter adapter = new NewsAdapter(getNews());//把模拟新闻数据传入到NewsAdapter构造函数中
newsTitleRecyclerView.setAdapter(adapter);//完成适配器设置
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.news_content_layout) != null) {
// 可以找到news_content_layout布局时,为双页模式
isTwoPane = true;
} else {
// 找不到news_content_layout布局时,为单页模式
isTwoPane = false;
}
}
/**
* 初始化50条模拟新闻数据
* @return
*/
private List<News> getNews() {
//创建集合
List<News> newsList = new ArrayList<>();
//实例化数据
for (int i = 1; i <= 50; i++) {
News news = new News();
news.setTitle("标题" + i);
news.setContent(getRandomLengthContent("东营职业学院电子信息与传媒学院" + i + ". "));
newsList.add(news);
}
return newsList;
}
/**
* 随机生成不同长度的新闻内容
* @param content
* @return
*/
private String getRandomLengthContent(String content) {
Random random = new Random();
int length = random.nextInt(20) + 1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
builder.append(content);
}
return builder.toString();
}
. . .
}
下面是双页模式
首先看过前几页第一行代码的敲友应该可以知道,在res下面新建layout-sw600dp文件夹系统就在屏幕分辨率大于600的时候自动选择该文件夹下的文件,在文件夹下面新建activity_main文件。(这里面有个坑,请绕行,我们新建的是layout-sw600dp文件夹,不是layout_sw600dp。layout后面不是下划线,是杠,是杠,是杠!)
<?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="horizontal">
<fragment
android:id="@+id/news_title_fragment"
android:name="com.yiyajing.mypremission.fragment.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.yiyajing.mypremission.fragment.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了一个FrameLayout布局下而这个布局的id正是news_content_layout,因此,能找到这个id就是双页模式,否则就是单页模式,双页模式情况下,系统会自动选择该布局。
实现效果图: