android实战简书,WanAndroid实战——首页文章

前面完成了首页Banner的实现,本次继续来完成首页文章的获取和显示。

按照惯例,先上实现过的效果图。

349da3f93c0c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

首页文章效果

1.相关布局文件

首页文章的展示使用的是recycleView,每一项使用的是cardview来进行,因此,先在gradle中引入需要的依赖。

//cardview

implementation 'com.android.support:cardview-v7:28.0.0'

//recycleview

implementation 'com.android.support:recyclerview-v7:28.0.0'

在activity_main.xml文件中添加recycleView的相关内容,修改后的文件如下:

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:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".view.MainActivity"

android:orientation="vertical">

android:id="@+id/main_banner"

android:layout_width="match_parent"

android:layout_height="@dimen/banner_height"/>

android:id="@+id/article_content"

android:layout_width="match_parent"

android:layout_height="match_parent"

/>

article_item.xml文件作为每一项的布局,这里使用cardView作为跟布局,文件内容和布局效果如下:

349da3f93c0c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

布局效果

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:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="@dimen/card_view_margin"

app:cardBackgroundColor="@color/card_view_bg_color"

app:cardCornerRadius="@dimen/card_view_corner_radius"

app:cardElevation="@dimen/card_view_elevation"

>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_margin="@dimen/article_item_constrain_margin">

android:id="@+id/guideline"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="vertical"

app:layout_constraintGuide_percent="0.79"/>

android:id="@+id/article_title"

style="@style/article_card_style"

android:layout_width="0dp"

android:layout_height="wrap_content"

app:layout_constraintEnd_toStartOf="@id/guideline"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toTopOf="parent"

tools:text="title"

/>

android:id="@+id/article_author"

style="@style/article_card_style"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_marginTop="@dimen/article_item_text_margin_top"

app:layout_constraintBottom_toTopOf="@id/article_classify"

app:layout_constraintEnd_toStartOf="@id/guideline"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/article_title"

tools:text="tom"

/>

android:id="@+id/article_classify"

style="@style/article_card_style"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_marginTop="@dimen/article_item_text_margin_top"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintEnd_toStartOf="@id/guideline"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/article_author"

tools:text="分类"

/>

android:id="@+id/article_time"

style="@style/article_card_style"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:gravity="end"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintEnd_toEndOf="parent"

tools:text="2010-00-00"

/>

android:id="@+id/article_collection"

android:layout_width="@dimen/article_item_collection"

android:layout_height="@dimen/article_item_collection"

android:src="@drawable/article_collect_selector"

app:layout_constraintBottom_toTopOf="@id/article_time"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintTop_toTopOf="parent"

tools:ignore="contentDescription"

/>

使用tools命名空间,用来展示布局效果,并且编译的时候不会编译进去,包括去掉一些警告,如ImageView的contentDescription属性。

使用Guideline,用来保证textView不会因为内容过长而遮挡其它控件的显示。

2.准备adapter

根据玩Android的开放API接口,我们知道首页数据的格式

可以直接复制示例内容后通过GsonFormat自动生成,具体的可以查看我的上一篇文章。生成的类名为MainArticleBean.java,记得加上toString方法,方便自己调试。

ArticleAdapter.java

package com.tom.wanandroid.adapter;

import android.content.Context;

import android.support.annotation.NonNull;

import android.support.v7.widget.RecyclerView;

import android.text.Html;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ImageView;

import android.widget.TextView;

import com.tom.wanandroid.R;

import com.tom.wanandroid.bean.MainArticleBean;

import java.util.List;

import butterknife.BindView;

import butterknife.ButterKnife;

/**

*

Title: ArticleAdapter

*

Description: 文章适配器

*

* @author tom

* @date 2019/3/9 10:15

**/

public class ArticleAdapter extends RecyclerView.Adapter {

private Context mContext;

private List mBeans;

public void setBeans(MainArticleBean beans) {

mBeans = beans.getData().getDatas();

}

public ArticleAdapter(RecyclerView recyclerView) {

mContext = recyclerView.getContext();

}

@NonNull

@Override

public ArticleHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

View view = LayoutInflater.from(mContext).inflate(R.layout.article_item, parent, false);

return new ArticleHolder(view);

}

@Override

public void onBindViewHolder(@NonNull ArticleHolder articleHolder, int i) {

if (mBeans != null) {

MainArticleBean.DataBean.DatasBean bean = mBeans.get(i);

articleHolder.mArticleTitle.setText(Html.fromHtml(bean.getTitle(), Html.FROM_HTML_MODE_COMPACT));

articleHolder.mArticleAuthor.setText(String.format(mContext.getResources().getString(R.string.article_author),bean.getAuthor()));

articleHolder.mArticleTime.setText(bean.getNiceDate());

String category = String.format(mContext.getResources().getString(R.string.article_category),

bean.getSuperChapterName(), bean.getChapterName());

articleHolder.mArticleClassify.setText(Html.fromHtml(category, Html.FROM_HTML_MODE_COMPACT));

}

}

@Override

public int getItemCount() {

return mBeans != null ? mBeans.size() : 0;

}

class ArticleHolder extends RecyclerView.ViewHolder {

@BindView(R.id.article_title)

TextView mArticleTitle;

@BindView(R.id.article_author)

TextView mArticleAuthor;

@BindView(R.id.article_classify)

TextView mArticleClassify;

@BindView(R.id.article_collection)

ImageView mArticleCollection;

@BindView(R.id.article_time)

TextView mArticleTime;

ArticleHolder(@NonNull View itemView) {

super(itemView);

ButterKnife.bind(this, itemView);

}

}

}

这里有一点需要说明,因为获取的数据为网络数据,且部分数据会带有html中的标签并且使用unicode编码,如果不处理的话会直接显示出unicode码,不好看。这里使用的是Html.fromHtml方法,里面的参数官网上面有说明。

3.在接口中增加相关的内容

分别增加MVP层的接口,比较简单,直接给出代码Contract.java。

package com.tom.wanandroid.contract;

import com.tom.wanandroid.bean.BannerBean;

import com.tom.wanandroid.bean.MainArticleBean;

import io.reactivex.Observable;

/**

*

Title: Contract

*

Description:

*

* @author tom

* @date 2019/3/7 10:13

**/

public class Contract {

public interface IMainModel {

/**

*

获取banner数据

* @return banner数据

*/

Observable loadBanner();

/**

*

获取首页文章

* @param number 页码

* @return 首页文章

*/

Observable loadArticle(int number);

}

public interface IMainView {

/**

*

View 获取到数据后进行显示

* @param bean banner的数据

*/

void loadBanner(BannerBean bean);

/**

*

展示首页文章信息

* @param bean 首页文章数据

*/

void loadArticle(MainArticleBean bean);

}

public interface IMainPresenter{

/**

*

首页banner

*/

void loadBanner();

/**

*

加载首页文章

*/

void loadArticle();

}

}

因为使用retorfit来获取网络数据,首先还是要增加接口。

IRetrofitData.java这里需要传入页码作为参数。

/**

*

获取首页文章数据

* @param number 页码

* @return 返回首页文章

*/

@GET("article/list/{number}/json")

Observable loadMainArticle(@Path("number") int number);

4.实现接口

接口加完以后,就来处理报错吧,哪里报错改哪里,so easy!

MainModel.java和之前获取首页数据一样的套路。

@Override

public Observable loadArticle(int number) {

Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.build();

IRetrofitData retrofitData = retrofit.create(IRetrofitData.class);

return retrofitData.loadMainArticle(number);

}

MainPresenter.java增加首页文章的相关内容,这里固定获取第一页的数据(传入参数为0)。

@Override

public void loadArticle() {

mModel.loadArticle(0)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer() {

@Override

public void onSubscribe(Disposable d) {

mCompositeDisposable.add(d);

}

@Override

public void onNext(MainArticleBean bean) {

if (isViewAttached()) {

getView().loadArticle(bean);

}

}

@Override

public void onError(Throwable e) {

e.printStackTrace();

}

@Override

public void onComplete() {

}

});

}

MainActivity.java,这里有一点小修改,将之前初始化数据的方法由init中放到了onresume中。

@Override

protected void onResume() {

super.onResume();

mPresenter.loadBanner();

mPresenter.loadArticle();

}

@Override

public void loadArticle(MainArticleBean bean) {

mArticleContent.setLayoutManager(new LinearLayoutManager(this));

if (bean.getErrorCode() == 0) {

ArticleAdapter adapter = new ArticleAdapter(mArticleContent);

adapter.setBeans(bean);

mArticleContent.setAdapter(adapter);

}

}

到这里为止,关键内容基本都OK了,程序跑起来就可以看到前面的效果图了。

这里给出用到的资源文件

colors.xml

#008577

#00574B

#D81B60

#F0F0F0

dimens.xml

200dp

12dp

15dp

10dp

10dp

15dp

30dp

strings.xml中文和英文是两个夹子的,这里写在一起了。

WanAndroid

author:%1$s

category:%1$s/%2$s

玩Android

作者:%1$s

分类:%1$s/%2$s

用到的图标:

349da3f93c0c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

collect_disable.png

349da3f93c0c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

collect_enable.png

后续更新:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值