這個項目主要有兩個功能,一個加載網頁/文章,另外一個用來顯示評論。並應用了MVP模式,Dagger2、RxJava、ButterKnife等開源框架。效果圖以下:java
首先來看一下佈局文件:android
<android.support.design.widget.CoordinatorLayout 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:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.dean.articlecomment.article.ArticleActivity">
<com.dean.articlecomment.ui.XAppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.dean.articlecomment.ui.XAppBarLayout>
<include layout="@layout/content_scrolling" />
<include layout="@layout/article_bottom_view" />
</android.support.design.widget.CoordinatorLayout>
在顯示網頁文章時是仿知乎的操做,向下滑動時隱藏toolbar和屏幕下方發表評論的視圖,向上滾動時再顯示。 git
toolbar的顯示隱藏是經過設置其scrollFlags屬性實現的。github
enterAlways:向上滑時toolbar隱藏,向下滑動即展現。 markdown
enterAlwaysCollapsed:向上滑時toolbar隱藏,向下滑動直到NestedScrollView的底部時toolbar才展現。 網絡
exitUntilCollapsed:當你定義了一個minHeight,這個view將在滾動到達這個最小高度的時候消失。app
snap:忽然折斷的意思,效果同enterAlwaysCollapsed,區別爲滾動時手指離開屏幕時
toolbar不會顯示一半的狀態,顯示的部分大於一半時即全漏出來,小於一半時即隱藏掉。框架
article_bottom_view是屏幕下方的評論條,它的隱藏顯示與toolbar同步,使用方式是經過AppBarLayout.OnOffsetChangedListener
的狀態監聽與動畫實現的。ide
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (verticalOffset >= 0) {
if (xAppBarListener != null) {
xAppBarListener.onFingerDown();
}
} else {
if (xAppBarListener != null) {
xAppBarListener.onFingerUp();
}
}
}
content_scrolling佈局以下:佈局
<com.dean.articlecomment.ui.XNestedScrollView 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:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_scrolling">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
<!--詳細-->
<FrameLayout android:id="@+id/article_content_view" android:layout_width="match_parent" android:layout_height="wrap_content">
</FrameLayout>
<!--評論-->
<FrameLayout android:id="@+id/comment_content_view" android:layout_width="match_parent" android:layout_height="wrap_content">
</FrameLayout>
</LinearLayout>
</com.dean.articlecomment.ui.XNestedScrollView>
NestedScrollView中嵌套兩個視圖article_content_view,comment_content_view。分別是用於顯示文章Fragment視圖和評論fragment視圖。
文章Fragment中使用Webview來顯示網頁/文章。
Webview使用了騰訊的X5WebView,並在外層封裝一個加載用的進度條。
文章Fragment中使用了RecycleView(根據XRecyclerView改造)來顯示添加評論,而且能夠進行滑動加載更多。
值得注意的是NestedScrollview中嵌套RecycleView的問題,解決方法是:
使用Android Support Library 23.2.0以上,設置layoutManager.setAutoMeasureEnabled(true);
將recyclerView的高度設置爲wrap_content
設置recyclerView.setNestedScrollingEnabled(false)
避免和NestedScrolling的滑動衝突。
因爲禁用了recyclerView的滾動,因此在實現底部加載更多的時候須要監聽外層的NestedScrollingView
本Demo使用了MVP模式(關於MVP的文章網上不少,我這裏就不過多介紹),主要借鑑了下面3個開源項目。並做了一些改動。
大多數MVP模式裏都是View持有Presenter的引用。一個fragment對應一個頁面,一個頁面對應一個Presenter,所以若是一個功能中頁面較多時會致使邏輯複雜以及代碼文件的增長。
我這裏的處理是反過來使Presenter持有View的引用,即一個Activity持有一個Presenter,每一個Fragment是一個View,用一個Presenter持有全部的View引用。
全部的邏輯和業務代碼都放在Presenter中處理,Activity和Fragment只負責頁面的顯示。這樣的好處是結構簡單,邏輯比較清晰,方便在多個view中交互操做。缺點就是會致使Presenter中代碼量過大。
代碼以下:
public class ArticlePresenter extends RxPresenter implements ArticleContract.Presenter {
protected final ArticleContract.ArticleView articleView;
protected final ArticleContract.CommentView commentView;
protected final ArticleContract.View bottomView;
@Inject
public ArticlePresenter(ArticleContract.ArticleView articleView, ArticleContract.CommentView commentView, ArticleContract.View bottomView) {
this.articleView = articleView;
this.commentView = commentView;
this.bottomView = bottomView;
}
@Inject
void setupListeners() {
// view中注入presenter
articleView.setPresenter(this);
commentView.setPresenter(this);
bottomView.setPresenter(this);
}
}
Contract代碼以下:
public interface ArticleContract {
interface Presenter extends BasePresenter {
void addComment();
void showBottomView();
void hideBottomView();
void onLoadingArticle();
void onLoadingComment();
void onLoadingMoreComment();
void onLoadingArticleSuccess();
void onLoadingArticleFailed();
}
interface CommentView extends BaseView<Presenter> {
void showComments(ArrayList<ArticleComment> comments);
void showLoadMoreComments(ArrayList<ArticleComment> comments);
void addComment(ArticleComment comment);
void onScrollToPageEnd();
}
interface ArticleView extends BaseView<Presenter> {
void showArticle(String url);
}
interface View extends BaseView<Presenter> {
void showBottomView();
void hideBottomView();
void goToComment();
void goToArticle();
}
}
Rxjava也是最近才知道。。。使用後發現是真的很牛逼。。。
因而也簡單的在這個Demo中應用了一下,加載更多評論的代碼以下:
@Override
public void onLoadingMoreComment() {
Subscription rxSubscription = Observable
.create(new Observable.OnSubscribe<ArrayList<ArticleComment>>() {
@Override
public void call(Subscriber<? super ArrayList<ArticleComment>> subscriber) {
ArrayList<ArticleComment> comments = new ArrayList<ArticleComment>();
for (int i = 0; i < 5; i++) {
ArticleComment newComment = new ArticleComment();
newComment.userName = "遊客" + i;
newComment.commentContent = "他很懶什麼都沒說。";
comments.add(newComment);
}
subscriber.onNext(comments);
}
})
.delay(2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ArrayList<ArticleComment>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ArrayList<ArticleComment> articleComments) {
if (commentView.isActive())
commentView.showLoadMoreComments(articleComments);
}
});
addSubscribe(rxSubscription);
}
Rxjava簡單使用很容易,但要達到能適應各類場景就不輕鬆了,我也在摸索中。下面列出我找到相關文章:
實話實說,這個依賴注入框架真心不太明白,感受學習成本和使用成本都有點高,demo裏也僅僅作了最簡單的應用。
下面列出我以爲不錯的文章:
依賴注入神器:Dagger2詳解系列
視圖注入框架,很好用!網上例子不少,使用起來也方便就不介紹了。
還有一些小細節,好比添加/刪除評論,雙擊toolbar回到文章頭,點擊評論按鈕跳轉到評論等等。寫這個demo的主要目的是爲了練習使用MVP以及各類開源框架,若是之後有時間會陸續加入下面列表中的開源框架。