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; } }
先准备好一个新闻的实体类,News类,title,content分别表示标题和内容。
接着新建布局文件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"/> <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:padding="15dp" android:textSize="18sp" /> </LinearLayout> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:background="#000"/> </RelativeLayout>
新闻内容布局由两部分组成,头部分显示新闻标题,正文部分显示新闻内容,中间用一条细线分开。
注意细线是通过View实现,
如图所示:
新建NewsContentFragment类,继承Fragment,代码如下:
public class NewsContentFragment extends Fragment {
private View view;
@Override
//onCreateView()方法加载了news_content_frag布局
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view=inflater.inflate(R.layout.news_content_frag,container,false);
return view;
}
//refresh方法,将新闻的标题和内容显示在界面上。这里通过findViewById()方法分别获取到新闻标题和内容的控件,然后将方法传递进来的参数设置进去。
public void refresh(String newsTitle,String newsContent){
View visibilityLayout=view.findViewById(R.id.visibility_layout);
visibilityLayout.setVisibility(View.VISIBLE);
TextView newsTitleText=(TextView) view.findViewById(R.id.news_title);
TextView newsContextText=(TextView) view.findViewById(R.id.news_content);
newsTitleText.setText(newsTitle);//刷新新闻的标题
newsContextText.setText(newsContent);//刷新新闻的内容
}
}
至此,新闻的内容碎片和布局都已创建,但都是基于双页模式中使用。
因此,必须创建单页模式下使用的布局和碎片。新建一个NewsContentActivity活动,并将布局指定为news_content,(此处需注意:我的Android Studio版本上,当创建NewsContentActivity活动时,会默认创建一个布局,但名字不是news_content,此处可以改名,通过右击——Refactor——Rename,即可更改成news_content),
修改news_content.xml的代码;
<LinearLayout 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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NewsContentActivity">
<fragment
android:id="@+id/news_content_fragment"
android:name="com.example.yt.fragmentpractice.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
android:name="com.example.yt.fragmentpractice.NewsContentFragment",直接在布局中引入NewsContentFragment,相当于把news_content_frag布局的内容自动加入进来。
修改NewsContentActivity代码;
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) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_content);
String newsTitle=getIntent().getStringExtra("news_title");//获取传入的新闻标题
String newsContent=getIntent().getStringExtra("news_content");//获取传入的新闻内容
NewsContentFragment newsContentFragment=(NewsContentFragment)getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(newsTitle,newsContent);
}
}
额,这里提供了一个actionStart方法,此方法是启动活动的最佳方法,可以非常清晰的了解需要传递的数据,简化了启动活动的代码。(现在可能还有点糊涂,但先记着,之后的会用到)
这里的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>
只有一个显示新闻列表的RecyclerView,还需要RecyclerView子项的布局,新建news_item.xml作为子项布局
<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:maxLines="1"
android:ellipsize="end"
android:textSize="18sp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"/>
android:padding表示给控件的周围加上补白
android:ellipsize用于设定当文本内容超出控件宽度时,文本的缩略的方式,这里指定成end,表示在尾部进行缩略。
至此新闻列表和子项的布局已经创建好,接下来创建一个用于展示新闻的列表的地方。这里新建NewsTitleFragment作为展示新闻列表的碎片:
public class NewsTitleFragment extends Fragment {
private boolean isTwoPane;
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.nws_title_frag,container,false);
RecyclerView newTitleRecyclerView=(RecyclerView)view.findViewById(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager=new LinearLayoutManager(getActivity());
newTitleRecyclerView.setLayoutManager(layoutManager);
NewsAdapter adapter=new NewsAdapter(getNews());
newTitleRecyclerView.setAdapter(adapter);
return view;
}
private List<News> getNews(){
List<News> newsList=new ArrayList<>();
for(int i=1;i<=50;i++){
News news=new News();
news.setTitle("This is news title "+i);
news.setContent(getRandomLengthContent("This is news content "+i+"."));
newsList.add(news);
}
return newsList;
}
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();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(getActivity().findViewById(R.id.news_content_layout)!=null){
isTwoPane=true;
}
else {
isTwoPane=false;
}
}
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(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
News news = mNewsList.get(holder.getAdapterPosition());
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());
}
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
News news=mNewsList.get(position);
holder.newsTitleText.setText(news.getTitle());
}
@Override
public int getItemCount() {
return mNewsList.size();
}
}
}
onCreateView加载了news_title_frag布局,onActivityCreated()方法,这个方法通过在活动中能否找到一个id为news_content_layout的View来判断当前是双页还是单页模式,因此我们需要让news_content_layout在双页模式中出现
首先修改activity_main.xml中的代码,在单页模式下,只会加载一个新闻的标题的碎片
<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"
tools:context=".MainActivity">
<fragment
android:id="@+id/news_title_fragment"
android:name="com.example.yt.fragmentpractice.NewsTitleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
单页模式下只会显示新闻标题一栏;
然后新建layout-sw600dp文件夹,在此文件夹下新建一个activity_main.xml文件; 建的文件名写全,为activity_main.xml,否则会显示错误。
言归正传:activity_main.xml代码
<LinearLayout 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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/news_title_fragment"
android:name="com.example.yt.fragmentpractice.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.example.yt.fragmentpractice.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
可见,在双页模式下我们同时引入了两个碎片,将新闻内容的碎片放在FrameLayout布局下,而这个布局的id是news_content_layout。因此,能找到这个id的时候就是双页模式,否则为单页模式。
最后一点,在NewsTitleFragment中通过RecyclerView将新闻列表展示出来,我们在NewsTitleFragment中新建一个内部类NewsAdapter来作为RecyclerView的适配器,onCreateView()方法中添加了RecyclerView标准的使用方法
分别在手机和平板上运行: