Android 资讯类App项目实战 第三章 新闻模块
前言:
正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。
以往的内容
第三章 新闻模块
本章内容最终效果:
新闻模块效果.gif知识点:
RecyclerView.Adapter,CoordinatorLayout,AppBarLayout,cardView,Glide,WebView
学习目标:
1、使用RecyclerView、cardView显示列表数据。
2、使用Glide加载图片。
3、WebView显示网页。
新闻模块是资讯类App的主体,主要内容包括新闻列表,新闻详情。
项目实战:
注意
本章用到的drawable资源、values资源皆存放在百度网盘
(请将values文件夹中的style.xml或color.xml更新一致后再运行,如有后续更新自行修改)
1.1 项目结构
本章增加的类和布局:
类
布局
需导入的库:
导入了cardView和图片加载库Glide。
1.2 item_news及适配器
新闻的显示需要用RecyclerView,所以先完成每个新闻item的代码。
新建一个布局文件,命名为item_news。
<?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="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_news_img"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/iv_news_img"
android:background="#34000000"
android:textColor="@color/colorWhite"
android:textSize="20dp"
android:typeface="serif" />
</RelativeLayout>
<TextView
android:id="@+id/tv_news_digest"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:maxLines="3"
android:textSize="16dp" />
</LinearLayout>
然后为我们的item_news写上适配器代码。
新建一个java文件,命名为ItemNewsAdapter。
public class ItemNewsAdapter extends RecyclerView.Adapter<ItemNewsAdapter.ItemNewsHolder> {
private List<NewsBean.Bean> objects = new ArrayList<NewsBean.Bean>();
private Context context;
public ItemNewsAdapter(Context context) {
this.context = context;
}
public void setData(List<NewsBean.Bean> objects) {
this.objects = objects;
}
@Override
public ItemNewsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_news, parent, false);
return new ItemNewsHolder(view);
}
@Override
public void onBindViewHolder(ItemNewsHolder holder, int position) {
NewsBean.Bean bean = objects.get(position);
if (bean == null) {
return;
}
Glide.with(context)
.load(bean.getImgsrc())
.into(holder.ivNewsImg);
if (position == 0) {
holder.tvNewsDigest.setVisibility(View.GONE);
holder.tvNewsTitle.setText("图片:" + bean.getTitle());
} else {
holder.tvNewsTitle.setText(bean.getTitle());
holder.tvNewsDigest.setText(bean.getMtime() + " : " + bean.getDigest());
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return objects.size();
}
protected class ItemNewsHolder extends RecyclerView.ViewHolder {
private ImageView ivNewsImg;
private TextView tvNewsTitle;
private TextView tvNewsDigest;
public ItemNewsHolder(View view) {
super(view);
ivNewsImg = (ImageView) view.findViewById(R.id.iv_news_img);
tvNewsTitle = (TextView) view.findViewById(R.id.tv_news_title);
tvNewsDigest = (TextView) view.findViewById(R.id.tv_news_digest);
}
}
}
这里面的图片加载用到的是Glide,这是谷歌推荐的图片加载库,加载速度快,引用也很简单。只需下面3行代码就能用。
Glide中间对控件的处理也是基于api返回的数据(网易新闻接口会图片新闻的数据),这里只是做了个简单的处理,具体优化还需要进一步分析接口数据。
item里显示的内容
1.3 RecycleView
接下来我们让刚才做的item在fragment里显示出来。
首先修改fg_news_list的布局代码,加入RecycleView:
fg_news_list.java
<?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="vertical">
<TextView
android:id="@+id/tv_news_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_news"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_news"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
然后修改FgNewsListFragment的代码:
FgNewsListFragment.java
public class FgNewsListFragment extends Fragment implements INewsView {
private NewsPresenter presenter;
private int type;
private SwipeRefreshLayout srl_news;
private RecyclerView rv_news;
private ItemNewsAdapter adapter;
private List<NewsBean.Bean> newsBeanList;
private TextView tv_news_list;
public static FgNewsListFragment newInstance(int type) {
Bundle args = new Bundle();
FgNewsListFragment fragment = new FgNewsListFragment();
args.putInt("type", type);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fg_news_list, null);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
type = getArguments().getInt("type");
presenter = new NewsPresenter(this);
rv_news = view.findViewById(R.id.rv_news);
adapter = new ItemNewsAdapter(getActivity());
tv_news_list = view.findViewById(R.id.tv_news_list);
srl_news = view.findViewById(R.id.srl_news);
srl_news.setColorSchemeColors(Color.parseColor("#ffce3d3a"));
srl_news.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
presenter.loadNews(type, 0);
}
});
presenter.loadNews(type, 0);
}
@Override
public void showNews(final NewsBean newsBean) {
switch (type) {
case FgNewsFragment.NEWS_TYPE_TOP:
newsBeanList = newsBean.getTop();
break;
case FgNewsFragment.NEWS_TYPE_NBA:
newsBeanList = newsBean.getNba();
break;
case FgNewsFragment.NEWS_TYPE_JOKES:
newsBeanList = newsBean.getJoke();
break;
}
adapter.setData(newsBeanList);
rv_news.setLayoutManager(new LinearLayoutManager(getActivity(),
LinearLayoutManager.VERTICAL, false));
rv_news.setAdapter(adapter);
tv_news_list.setVisibility(View.GONE);
}
@Override
public void hideDialog() {
srl_news.setRefreshing(false);
}
@Override
public void showDialog() {
srl_news.setRefreshing(true);
}
@Override
public void showErrorMsg(String error) {
tv_news_list.setText("加载失败:" + error);
}
}
效果:
新闻模块效果1.gif1.4 CardView
每一个新闻怎么做到卡片显示呢?这里我们用到了控件cardView。
cardView的使用非常简单,我把一些设置直接写在布局里了,不需要写别的逻辑代码,只要把item_news里的东西包裹进去就好了。
item_news.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardCornerRadius="5dp"
app:cardElevation="10dp"
android:layout_margin="10dp"
android:id="@+id/cv_news"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_news_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/tv_news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:typeface="serif"
android:background="#34000000"
android:textColor="@color/colorWhite"
android:layout_alignBottom="@+id/iv_news_img" />
</RelativeLayout>
<TextView
android:id="@+id/tv_news_digest"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:textSize="16dp"
android:maxLines="3"/>
</LinearLayout>
</android.support.v7.widget.CardView>
效果:
新闻模块效果2.gif
2.1 CoordinatorLayout与AppBarLayout
当滑动列表的时候,为了给屏幕腾出更多空间,上面的导航栏会有折叠的效果,这里就要用到CoordinatorLayout和AppBarLayout了。
到main_content文件里将最外层包裹上CoordinatorLayout,在将Toolbar放进AppBarLayout:
main_content.xml
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/view_status"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:visibility="gone"></View>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbars"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorTheme"
app:contentInsetStart="0dp"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_title_news"
android:layout_width="55dp"
android:layout_height="match_parent"
android:padding="15dp"
android:src="@drawable/titlebar_news" />
<ImageView
android:id="@+id/iv_title_movie"
android:layout_width="55dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:padding="13dp"
android:src="@drawable/titlebar_movie" />
<ImageView
android:id="@+id/iv_title_video"
android:layout_width="55dp"
android:layout_height="match_parent"
android:padding="15dp"
android:src="@drawable/titlebar_video" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="5dp"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v4.view.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
AppBarLayout里有一个elevation属性,可以将bar浮起来,既然Toolbar浮到5,那么把fg_news里的TabLayout也浮到5吧。
fg_news.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.TabLayout
android:id="@+id/tl_news"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/colorTheme"
app:tabIndicatorColor="@color/colorWhite"
app:tabSelectedTextColor="@color/colorWhite"
app:tabTextColor="@color/colorTabTextNormal" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp_news"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
效果:
往上滑的是候最上面的导航会折叠
3.1 WebView打开新闻详情网页
点击每个新闻卡片后,出现的新闻详情我直接用WebView显示。
新建布局文件a_detail(新增加的图片资源到我上面的网盘地址里找):
a_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="@color/colorTheme">
<ImageView
android:id="@+id/iv_back"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/back" />
<TextView
android:id="@+id/tv_bar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:maxLines="1"
android:textColor="@color/colorWhite"
android:textSize="20sp" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<WebView
android:id="@+id/wb_news"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/pb_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
style="@style/common_mProgress_circle"
/>
</FrameLayout>
然后写WebView的Activity代码:
ADetailActivity.java
public class ADetailActivity extends Activity {
private WebView wbNews;
private String loadUrl, title;
private WebViewClient webViewClient;
private TextView tv_bar_title;
private ImageView iv_back;
private ProgressBar pb_load;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.a_detail);
loadUrl = getIntent().getStringExtra("url");
title = getIntent().getStringExtra("title");
initView();
setWebViewClient();
}
private void setWebViewClient() {
webViewClient = new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
pb_load.setVisibility(View.VISIBLE);
}
@Override
public void onPageFinished(WebView view, String url) {
pb_load.setVisibility(View.GONE);
}
};
wbNews.setWebViewClient(webViewClient);
}
private void initView() {
wbNews = (WebView) findViewById(R.id.wb_news);
wbNews.getSettings().setJavaScriptEnabled(true);
wbNews.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
wbNews.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
wbNews.canGoBack();
wbNews.canGoForward();
wbNews.loadUrl(loadUrl);
tv_bar_title = (TextView) findViewById(R.id.tv_bar_title);
tv_bar_title.setText(title);
iv_back = (ImageView) findViewById(R.id.iv_back);
iv_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
pb_load = (ProgressBar) findViewById(R.id.pb_load);
}
@Override
protected void onDestroy() {
super.onDestroy();
wbNews.destroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == event.KEYCODE_BACK && wbNews.canGoBack()) {
wbNews.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
在ItemNewsAdapter里把跳转页面的代码补上:
ItemNewsAdapter.java到manifest文件中声明Activity:
AndroidManifest.xml效果:
新闻模块效果4.gif
本章的新闻模块显示的列表数量是有限的,这是因为还没做“加载更多”的功能,这些在以后有时间在慢慢优化。
上一章:
第二章 滑动顶部导航栏