Android学习之简易版的新闻应用
•准备工作
新建一个项目,命名为 FragmentBestProject,并选择 Empty Activity;
并将项目的模式结构改为 Project 模式;
•进入主题
首先,准备好一个新闻实体类,新建类 News;
News.java
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;
}
}title 表示新闻标题,content 表示新闻内容;
接着新建布局文件 news_content_frag.xml,用于作为新闻内容的布局;
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:textSize="20sp"
/> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/black"/> <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="@color/black"
/> </RelativeLayout>新闻的内容部分主要可以分为两个部分:
- 头部部分显示新闻标题
- 正文部分显示新闻内容
- 中间使用一条细线分隔开(利用 View 来实现)
- 左侧一条竖线区分标题列表(利用 View 来实现)
下面提供了双页模式和单页模式的布局示意图,双页和单页模式下文会讲,莫着急;
双页模式示意图:
单页模式示意图:
在新建一个 NewsContentFragment 类,继承自 Fragmet;
NewsContentFragment.java
public class NewsContentFragment extends Fragment { private View view;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable 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 = view.findViewById(R.id.news_title);
TextView newsContentText = view.findViewById(R.id.news_content); newsTitleText.setText(newsTitle);//刷新新闻的标题
newsContentText.setText(newsContent);//刷新新闻的内容
}
}首先在 onCreateView() 方法里加载了我们刚刚创建的 news_content_frag 布局;
接下来又提供了一个 refresh() 方法;
这个方法就是用于将新闻的标题和内容显示在界面上;
这里通过 view.findViewById() 方法分别获取新闻的标题和内容控件,并通过 setText() 将传递的参数设置上;
到目前为止,我们就把新闻内容的碎片和布局都创建好了;
但上述布局都是在双页模式中使用的,如果想在单页模式中启动的话,我们还需要在创建一个活动;
新建一个 Empty Activity,命名为 NewsContentActivity,并将布局名指定为 news_content;
修改 news_content.xml 中的代码;
news_content.xml
<?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"> <fragment
android:id="@+id/news_content_fragment"
android:name="com.example.fragmentbestproject.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/> </LinearLayout>此处代码充分发挥了代码的复用性,直接在布局中通过 android:name 属性引入 NewsContentFragment;
这样也就相当于把 news_content_frag 布局的内容自动添加进来;
接下来修改 NewsContentActivity.java 中的代码;
NewsContentActivity.java
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"); //获取news_content中的fragment
NewsContentFragment newsContentFrgment =
(NewsContentFragment) getSupportFragmentManager()
.findFragmentById(R.id.news_content_fragment); newsContentFrgment.refresh(newsTitle,newsContent);//刷新NewsContentFragment界面
}
}可以看到,在 onCreate() 方法中,我们通过 Intent 获取到了传入的新闻标题和内容;
然后调用 FragmentManager 的 findFragmentById() 方法得到了 NewsContentFragment 实例;
接着调用它的 refresh() 方法,并将新闻的标题和内容传入,就可以把这些数据显示出来了;
这里我们还提供了一个 actionStart() 方法,有关该方法的使用,可以参考我的这篇博客;
接下来创建一个用于显示新闻列表的布局,新建 news_title_frag.xml;
news_title_frag.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView
android:id="@+id/news_title_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </LinearLayout>这个布局的代码就非常简单,里面只有一个用于显示新闻列表的 RecyclerView。
新建 news_item.xml 作为 RecyclerView 子项的布局;
news_item.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"
/>子项布局的代码也非常简单,只有一个 TextView。
代码进行到这,新闻列表和子项布局都已经创建好了;
接下来我们就需要一个用于展示新闻列表的地方;
新建一个 NewsTitleFragment 类作为展示新闻列表的碎片;
NewsTitleFragment.java
public class NewsTitleFragment extends Fragment { private boolean isTwoPane;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag,container,false);
return view;
} @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//通过判断是否可以找到 news_content_layout 布局来判定是单页模式还是双页模式
if(getActivity().findViewById(R.id.news_content_layout) != null){
isTwoPane = true;//找到->双页模式
}
else
isTwoPane = false;//未找到->单页模式
}
}在 onCreateView() 方法中加载了 news_title_frag 布局;
在 onActivityCreated() 方法中,通过在活动中能否找到 news_content_layout 布局来判定是什么模式;
屏幕前的你是不是在往上扒拉代码,看看 news_content_layout 在哪个文件里?
其实,他还未出现,在下面代码里呢;
修改 activity_main.xml 中的代码;
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"> <fragment
android:id="@+id/news_title_fragment"
android:name="com.example.fragmentbestproject.NewsTitleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </FrameLayout>该代码表示,在单页模式下,只会加载一个新闻标题的碎片;
然后,新建 layout-sw600dp 文件夹,在这个文件夹下新建一个 activity_main.xml 文件;
sw600dp\activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"> <fragment
android:id="@+id/news_title_fragment"
android:name="com.example.fragmentbestproject.NewsTitleFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<LinearLayout
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.fragmentbestproject.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
</LinearLayout>可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了 LinearLayout 布局下;
注意看这个 <LinearLayout> 布局的 id,你发现了什么?
现在我们已经将绝大部分工作都完成了,但还剩下至关重要的一点;
就是在 NewsTitleFragment 中通过 RecyclerView 将新闻展示出来;
现在,我们在 NewsTitleFragment.java 中新建一个内部类 NewsAdapter 来作为 RecyclerView 的适配器;
NewsTitleFragment.java
public class NewsTitleFragment extends Fragment { private boolean isTwoPane; ..........
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder>{
private List<News> mNewsList; class ViewHolder extends RecyclerView.ViewHolder{
TextView newsTitleText;
public ViewHolder(@NonNull View view) {
super(view);
newsTitleText = view.findViewById(R.id.news_title);
}
} public NewsAdapter(List<News> list){
mNewsList = list;
} @NonNull
@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());
//通过 isTwoPane 的取值判断是单页模式还是双页模式
if(isTwoPane){
/**
* isTwoPane == true
* 双页模式,刷新 NewsContentFragment 中的内容
*/
NewsContentFragment newsContentFragment =
(NewsContentFragment) getFragmentManager()
.findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(news.getTitle(),news.getContent());
}
else{
/**
* isTwoPane == false
* 单页模式,直接启动 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();
}
}
}需要注意的是,之前都是将适配器写成一个独立的类,而这次写成了内部类;
本次写成内部类的好处就是可以直接访问 isTwoPlane ;
观察 onCreateViewHolder() 方法中注册的点击事件;
首先获取到了被点击项的 News 实例,然后通过 isTwoPlane 判断模式;
如果是单页模式,就启动一个新的活动显示新闻内容;
如果是双页模式,就更新新闻内容碎片里的数据;
到目前为止,此次项目接近尾声,仅剩下最后一步的收尾工作——向 RecyclerView 中填充数据;
修改 NewsTitleFragment.java 中的代码;
public class NewsTitleFragment extends Fragment { private boolean isTwoPane;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag,container,false);
RecyclerView rv = view.findViewById(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
rv.setLayoutManager(layoutManager);
NewsAdapter adapter = new NewsAdapter(getNews());
rv.setAdapter(adapter);
return view;
} @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//通过判断是否可以找到 news_content_layout 布局来判定是单页模式还是双页模式
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(@NonNull View view) {
super(view);
newsTitleText = view.findViewById(R.id.news_title);
}
} public NewsAdapter(List<News> list){
mNewsList = list;
} @NonNull
@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());
//通过 isTwoPane 的取值判断是单页模式还是双页模式
if(isTwoPane){
/**
* isTwoPane == true
* 双页模式,刷新 NewsContentFragment 中的内容
*/
NewsContentFragment newsContentFragment =
(NewsContentFragment) getFragmentManager()
.findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(news.getTitle(),news.getContent());
}
else{
/**
* isTwoPane == false
* 单页模式,直接启动 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();
}
} private List<News> getNews(){
List<News> list = new ArrayList<>();
for(int i = 1;i <= 10;i++){
News news = new News();
news.setTitle("title "+i);
news.setContent("this is news content "+i+".");
list.add(news);
}
return list;
}
}这样,我们所有的编写工作就已经完成了,快来试一下吧!
运行结果
Tablet
Phone
•小结
最后,让我们站在上帝视角总结一下这次的设计;
首先,新建一个包含 Empty Activity 的项目,命名为 FragmentBestProject;
为了能实现在手机上单页显示,在平板上双页显示,又新建了一个 layout-sw600dp 文件夹;
并在这个文件夹里新建了一个 activity_main.xml;
接下来该为界面设计标题和内容布局了;
考虑到一点,不论是单页模式,还是双页模式,都会有新闻标题的身影;
所以,我们新建 news_title_frag.xml,并配套新建了 NewsTitleFragment 用来显示该布局;
新建完显示 title 的文件,接下来该新建显示 content 的文件了;
新建 news_content_frag.xml,并配套新建了 NewsContentFragment 用来显示该布局;
双页模式下点击 title 直接在右边显示相应的 content;
而单页模式需要为 title 设置相应的点击跳转事件;
点击 title 开启对应的新的活动;
新建一个 Empty Activity,设置类名为 NewsContentActivity,布局文件名为 news_content;
这个新建的活动代表点击 title 跳转的新活动;
到这,有趣的图解式就结束了,接下来就是为页面添加数据了;
枯燥无味的东西不想再写第二遍了,看上面的 Adapter 就可以了;
画图不易,码字不易,求多支持,最后附上该图的 .psd 文件。
最新文章
- Zbrush 快捷键
- SQL Server2008附加数据库之后显示为只读
- Unity3D 游戏开发构架篇 ——角色类的设计与持久化
- 使用next-key locks 用于搜索和索引扫描,可以防止幻读
- 【Howie玩docker】-命令行只显示-bash-4.1#
- day4 liaoxuefeng---高级特性
- C#反射与特性使用简介
- [转帖]Docker容器CPU、memory资源限制
- Centos6.8 安装nginx
- Gsoap编译
- Java性能分析神器-JProfiler详解(一)(转)
- 通过DBMS_REDEFINITION包对表在线重定义
- Python 实现双向链表(图解)
- java stream collector
- CSS 学习路线(二)选择器
- HNOI2018 退役记
- SQL数据库有阻塞就自动发邮件警报
- Python subplot 绘画
- spark第七篇:Spark SQL, DataFrame and Dataset Guide
- HDOJ.2064 汉诺塔III
热门文章
- js 深入原理讲解系列-currying function
- tree ignore &; bash &; cmd
- Object to Array
- c++ string与wstring转换
- BGV币与YFI币、YFII币存在着怎样的相关性?
- python的with用法(转载)
- 【HTB靶场系列】靶机Carrier的渗透测试
- 无所不能的Embedding7 - 探索通用文本表达[FastSent/InferSent/GenSen/USE]
- 【翻译】Python PEP8编码规范(中文版)
- 【JAVA并发第四篇】线程安全