Android 资讯类App项目实战 第三章 新闻模块

前言:

正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。

以往的内容

第一章 滑动顶部导航栏

第二章 retrofit获取网络数据

第三章 新闻模块

本章内容最终效果:

新闻模块效果.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。

build.gradle

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.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"
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.gif

1.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

本章的新闻模块显示的列表数量是有限的,这是因为还没做“加载更多”的功能,这些在以后有时间在慢慢优化。

项目源码:https://github.com/Huigesi/IdleReaderDemo

上一章:
第二章 滑动顶部导航栏

下一章:
第四章 电影模块

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,088评论 2 44
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    wgl0419阅读 6,126评论 1 9
  • 相关连接:深入理解RunLoopIOS---实例化讲解RunLoopiOS知识点整理-RunLoopRunLoop...
    大布溜阅读 242评论 0 0
  • 春天,回去看望婆婆,婆婆出生在穷苦人家,生活非常的节俭,舍不得吃喝。一个人的时候,一天只做一顿早饭,一锅粥,分三顿...
    四叶草_广广阅读 368评论 8 7