碎片的最佳实践——一个简易版的新闻应用
来源:互联网 发布:如何成为网络强国 编辑:程序博客网 时间:2024/06/05 02:49
现在你已经将关于碎片的重要知识点都掌握得差不多了,不过在灵活运用方面可能还有些欠缺,因此又该进入最佳实践环节了。
前面有提到过,碎片很多时候都是在平板开发当中使用的,主要是为了解决屏幕空间不能充分利用的问题。那是不是就表明,我们开发的程序都需要提供一个手机版和一个 Pad 版呢?确实有不少公司都是这么做的,但是这样会浪费很多的人力物力。因为维护两个版本的代码成本很高,每当增加什么新功能时,需要在两份代码里各写一遍,每当发现一个 bug 时,需要在两份代码里各修改一次。因此今天我们最佳实践的内容就是,教你如何编写同时兼容手机和平板的应用程序。
现在我们就讲运用所学的知识来编写一个简易版的新闻英语,并且要求它是可以同时兼容手机和平板的。新建好一个 FragmentBestPractice 项目,然后开始手动吧!
第一步我们要先准备好一个新闻的实体类,新建类 News,代码如下所示:
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 类的代码还是比较简单的,title 字段表示新闻标题,content 字段表示新闻内容。接着新建一个 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>
这段代码也非常简单,只是在 LinearLayout 中放入了一个 TextView 用于显示新闻的标题。仔细观察 TextView,你会发现其中有几个属性时我们之前没有学过的。Android:padding 表示给控件的周围加上补白,这样不至于让文本内容会紧靠在边缘上。android:singleLine 设置为 true 表示让这个 TextView 只能单行显示。android:ellipsize 用于设定当文本内容超出控件宽度时,文本的缩略方式,这里指定成 end 表示在尾部进行缩略。
接下来需要创建新闻列表的适配器,让这个适配器继承自 ArrayAdapter,并将泛型指定为 News 类。新建类 NewsAdapter,代码如下所示:
public class NewsAdapter extends ArrayAdapter<News> { private int resourceId; public NewsAdapter(Context context, int textViewResourceId, List<News> 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 类,并让新闻的标题在列表中进行显示。
这样基本就把新闻列表部分的代码编写完了,接下来我们看一下如何编写新闻内容部分的代码。新建布局文件 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="1dp" android:scaleType="fitXY" android:src="@drawable/spilt_line" /> <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="1dp" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:scaleType="fitXY" android:src="@drawable/spilt_line_vertical" /> </RelativeLayout>
新闻内容的布局主要可以分为两个部分,头部显示完整的新闻标题,正文部分显示新闻内容,中间使用一条细线分割开。这里的细线是利用 ImageView 显示了一张很窄的图片来实现的,将 ImageView 的 android:scaleType 属性设置为 fitXY,表示让这张图片填充满整个控件的大小。
然后再新建一个 NewsContentFragment 类,继承自 Fragment,代码如下所示:
public class NewsContentFragment extends Fragment { private View view; @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) view.findViewById(R.id.news_title); TextView newsContentText = (TextView) view .findViewById(R.id.news_content); newsTitleText.setText(newsTitle); newsContentText.setText(newsContent); } }
首先在 onCreateView() 方法里加载了我们刚刚创建的 news_content_frag 布局,这个没什么好解释的。接下来又提供了一个refresh() 方法,这个方法就是用于将新闻的标题和内容显示在界面上的。可以看到,这里通过 findViewById() 方法分别获取到新闻的标题和内容控件,然后将方法传递进来的参数设置进去。
接着要创建一个在 Activity 中使用的新闻内容布局,新建 news_content.xml,代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <fragment android:id="@+id/news_content_fragment" android:name="com.example.fragmentbestpractice.NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
这里我们充分发挥了代码的复用性,直接在布局中引入了 NewsContentFragment,这样也就相当于把 news_content_frag 布局的内容自动加了进来。
然后新建 NewsContentActivity,作为显示新闻内容的 Activity,代码如下所示:
public class NewsContentActivity extends Activity { 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); requestWindowFeature(Window.FEATURE_NO_TITLE); 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); } }
可以看到,在 onCreate() 方法中我们通过 Intent 获取到了传入的新闻标题和新闻内容,然后调用 FragmentManager 的 findFragmentById() 方法得到了 NewsContentFragment 的实例,接着调用它的 refresh() 方法,并将新闻的标题和内容传入,就可以把这些数据显示出来了。这一这里我们还提供了一个 actionStart() 方法。
接下来还需要再创建一个用于显示新闻列表的布局,新建 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>这个布局的代码就非常简单了,里面只有一个 ListView。不过想必你已经猜到了,这个布局并不是给 Activity 使用的,而是给碎片使用的,因此我们还需要创建一个碎片来加载这个布局。新建一个 NewsTitleFragment 类,继承自 Fragment,代码如下所示:
public class NewsTitleFragment extends Fragment implements OnItemClickListener { private ListView newsTitleListView; private List<News> 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); } @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 { // 如果是单页模式,则直接启动 NewsContent NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent()); } } private List<News> getNews() { List<News> newsList = new ArrayList<News>(); News news1 = new News(); news1.setTitle("Succeed in College as a Learning Disabled Student"); news1.setContent("College freshmen will soon learn to live with a roommate, adjust to a new social scene and survive less-than-stellar dining hall food. Students with learning disabilities will face these transitions while also grappling with a few more hurdles."); newsList.add(news1); News news2 = new News(); news2.setTitle("Google Android exec poached by China's Xiaomi"); news2.setContent("China's Xiaomi has poached a key Google executive involved in the tech giant's Android phones, in a move seen as a coup for the rapidly growing Chinese smartphone maker."); newsList.add(news2); return newsList; } }
这个类的代码有点长,我来重点解释一下。根据碎片的生命周期,我们知道,onAttach() 方法会首先执行,因此在这里做了一些数据初始化操作,比如调用 getNews() 方法获取几条模拟的新闻数据,以及完成 NewsAdapter 的创建。然后在 onCreateView() 方法中加载了 news_title_frag 布局,并给新闻列表的 ListView 注册了点击事件。接下来在 onActivityCreated() 方法中,我们通过是否能够找到一个 id 为 news_content_layout 的 View 来判断当前是双页模式还是单页模式,这个 id 为 news_content_layout 的 View 只在双页模式中才会出现,在稍后的布局里你将会看到。然后在 ListView 的点击事件里我们就可以判断,如果当前是单页模式,就启动一个新的 Activity 去显示新闻内容,如果当前是双页模式,就更新新闻内容碎片里的数据。
剩下工作就非常简单了,修改 activity_main.xml 中的代码,如下所示:
<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_title_fragment" android:name="com.example.fragmentbestpractice.NewsTitleFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>上述代码表示,在单页模式下,只会加载一个新闻标题的碎片。然后新建 layout-sw600dp 文件夹,在这个 文件夹下再新建一个 activity_main.xml 文件,代码如下所示:
<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_title_fragment" android:name="com.example.fragmentbestpractice.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.fragmentbestpractice.NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> </LinearLayout>
可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了一个 FrameLayout 布局下,而这个布局的 id 正是 news_content_layout。因此,能够找到这个 id 的时候就是双页模式,否则就是单页模式。
最后再将 MainActivity 稍作修改,把标题栏去除掉,代码如下所示:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); } }这样我们所有的编写工作就已经完成了,赶快来运行一下吧!首先在手机模拟器上运行,效果如图 4.15 所示。
图 4.15
可以看到两条新闻的标题,并且超出屏幕部分的文字是在尾部使用省略号代替的。
然后点击第二条新闻,会启动一个新的 Activity 来显示新闻的内容,效果如图 4.16 所示。
图 4.16
接下来将程序在平板模拟器上运行,同样点击第二条新闻,效果如图 4.17 所示。
图 4.17
怎么样?同样的一份代码,在手机和平板上运行却分别是两种完全不同的效果,说明我们程序的兼容性已经写得相当不错了。
摘自《第一行代码》
- 碎片的最佳实践——简易版新闻应用
- 碎片的最佳实践——一个简易版的新闻应用
- 碎片的最佳实践——一个简易版的新闻应用
- Fragment最佳实践---------一个简易版的新闻应用
- 第 4 章 探究碎片最佳实践之简易版的新闻应用
- 【安卓学习】4.碎片(Fragment)实践---一个简单的新闻应用。
- 碎片实例:简易版本的新闻应用(碎片+列表显示的问题)
- 学习了《第一行代码》4.5章—一个简易版的新闻应用
- 《碎片的最佳实践》读书笔记
- 关于一个简易的新闻应用的感悟
- 一个简易版的新闻应用(同时兼容手机和平板)
- 品牌推广应用设计的最佳实践
- iOS应用设计的一些最佳实践
- react实战:一个极简易的新闻站点
- 删除一个OSD的最佳实践
- Android学习笔记五—简易新闻应用设计
- SwiSH max——简易动画制作的最佳选择
- Fragment碎片应用--新闻APP
- leetcode路径的和是否等于某一个数
- BigDecimal
- linux命令大全 find
- tree数据格式封装处理
- 面向对象_类名作为形式参数
- 碎片的最佳实践——一个简易版的新闻应用
- css浏览器兼容大全
- 虚拟机
- java编程思想读书笔记 第十四章 类型信息(中)
- 堆和栈的概念
- linux命令大全 which
- java--JSTL(2)
- spring boot mvc单元测试
- 网络部第一次升华培训