1.预览效果
1.1.首先看一下需要实现的效果。
第一种,文字类型新闻。
第二种,图片类型新闻。
1.2.在NewsArticleTextViewBinder中设置了点击事件
RxView.clicks(holder.itemView) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer<Object>() { @Override public void accept(@io.reactivex.annotations.NonNull Object o) throws Exception { NewsContentActivity.launch(item); } });
所以每个item,点击之后会执行accept中的跳转。
2.新闻详情之纯文本的活动
2.1.源代码
public class NewsContentActivity extends BaseActivity { private static final String TAG = "NewsContentActivity"; private static final String IMG = "img"; public static void launch(MultiNewsArticleDataBean bean) { InitApp.AppContext.startActivity(new Intent(InitApp.AppContext, NewsContentActivity.class) .putExtra(TAG, bean) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } public static void launch(MultiNewsArticleDataBean bean, String imgUrl) { InitApp.AppContext.startActivity(new Intent(InitApp.AppContext, NewsContentActivity.class) .putExtra(TAG, bean) .putExtra(IMG, imgUrl) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container); Intent intent = getIntent(); getSupportFragmentManager().beginTransaction() .replace(R.id.container, NewsContentFragment.newInstance(intent.getParcelableExtra(TAG), intent.getStringExtra(IMG))) .commit(); } }
2.2.外部传进去一个MultiNewsArticleDataBean类型,来执行跳转。
2.3.外部传进去一个MultiNewsArticleDataBean类型+url,来执行跳转。
2.4.这个活动的onCreate,将这个活动的布局用某一个碎片来代替。
所以用哪个碎片来代替是我们即将要考虑的。
2.5.这里在清单中配置这个活动要特别注意:
这个风格一定要是没有标题栏的。
首先在清单中声明:
<activity android:name=".module.news.content.NewsContentActivity" android:configChanges="orientation|screenSize|uiMode" android:label="@string/title_news_content" android:theme="@style/AppTheme.NoActionBar.Slidable"/>
然后在资源文件的styles.xml进行声明这个style
<style name="AppTheme.NoActionBar.Slidable" parent="AppTheme.NoActionBar"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> </style>
3.新闻详情片段Fragment
3.1.源代码
package com.jasonjan.headnews.module.news.content; import android.annotation.SuppressLint; import android.content.Intent; import android.graphics.Color; import android.graphics.PorterDuff; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CollapsingToolbarLayout; import android.support.design.widget.Snackbar; import android.support.v4.widget.ContentLoadingProgressBar; import android.support.v4.widget.NestedScrollView; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ImageView; import com.jasonjan.headnews.R; import com.jasonjan.headnews.bean.news.MultiNewsArticleDataBean; import com.jasonjan.headnews.global.Constant; import com.jasonjan.headnews.main.ErrorAction; import com.jasonjan.headnews.main.IntentAction; import com.jasonjan.headnews.module.base.BaseFragment; import com.jasonjan.headnews.util.ImageLoader; import com.jasonjan.headnews.util.SettingUtil; import com.jasonjan.headnews.widget.AppBarStateChangeListener; /** * Created by JasonJan on 2018/1/8. */ public class NewsContentFragment extends BaseFragment<INewsContent.Presenter> implements INewsContent.View{ private static final String TAG = "NewsContentFragment"; private static final String IMG = "img"; // 新闻链接 标题 头条号 文章号 媒体名 private String shareUrl; private String shareTitle; private String mediaUrl; private String mediaId; private String mediaName; private String imgUrl; private boolean isHasImage; private MultiNewsArticleDataBean bean; private Toolbar toolbar; private WebView webView; private NestedScrollView scrollView; private INewsContent.Presenter presenter; private ContentLoadingProgressBar progressBar; private AppBarLayout appBarLayout; private CollapsingToolbarLayout collapsingToolbarLayout; private ImageView imageView; private SwipeRefreshLayout swipeRefreshLayout; public static NewsContentFragment newInstance(Parcelable dataBean, String imgUrl) { NewsContentFragment instance = new NewsContentFragment(); Bundle bundle = new Bundle(); bundle.putParcelable(TAG, dataBean); bundle.putString(IMG, imgUrl); instance.setArguments(bundle); return instance; } @Override protected int attachLayoutId() { imgUrl = getArguments().getString(IMG); isHasImage = !TextUtils.isEmpty(imgUrl); return isHasImage ? R.layout.fragment_news_content_img : R.layout.fragment_news_content; } @Override protected void initView(View view){ toolbar = view.findViewById(R.id.toolbar); initToolBar(toolbar, true, ""); toolbar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { scrollView.smoothScrollTo(0, 0); // ObjectAnimator anim = ObjectAnimator.ofInt(webView, "scrollY", webView.getScrollY(), 0); // anim.setDuration(500).start(); } }); webView = view.findViewById(R.id.webview); initWebClient(); scrollView = view.findViewById(R.id.scrollView); scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { @Override public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { onHideLoading(); } }); progressBar = view.findViewById(R.id.pb_progress); int color = SettingUtil.getInstance().getColor(); progressBar.getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.MULTIPLY); progressBar.show(); swipeRefreshLayout = view.findViewById(R.id.refresh_layout); swipeRefreshLayout.setColorSchemeColors(SettingUtil.getInstance().getColor()); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { swipeRefreshLayout.post(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(true); } }); presenter.doLoadData(bean); } }); if (isHasImage) { appBarLayout = view.findViewById(R.id.app_bar_layout); collapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar); imageView = view.findViewById(R.id.iv_image); } setHasOptionsMenu(true); } @Override protected void initData(){ Bundle bundle=getArguments(); try{ bean=bundle.getParcelable(TAG); presenter.doLoadData(bean); shareUrl = !TextUtils.isEmpty(bean.getShare_url()) ? bean.getShare_url() : bean.getDisplay_url(); shareTitle = bean.getTitle(); mediaName = bean.getMedia_name(); mediaUrl = "http://toutiao.com/m" + bean.getMedia_info().getMedia_id(); mediaId = bean.getMedia_info().getMedia_id(); }catch (Exception e){ ErrorAction.print(e); } if(isHasImage){ ImageLoader.loadCenterCrop(getActivity(), bundle.getString(IMG), imageView, R.mipmap.error_image, R.mipmap.error_image); appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { @Override public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State state) { if (state == State.EXPANDED) { // 展开状态 collapsingToolbarLayout.setTitle(""); toolbar.setBackgroundColor(Color.TRANSPARENT); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } } else if (state == State.COLLAPSED) { // 折叠状态 } else { // 中间状态 collapsingToolbarLayout.setTitle(mediaName); toolbar.setBackgroundColor(SettingUtil.getInstance().getColor()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } } } }); }else{ toolbar.setTitle(mediaName); } } @Override public void onPause() { super.onPause(); if (isHasImage) { appBarLayout.setExpanded(false); } } @SuppressLint("SetJavaScriptEnabled") private void initWebClient() { WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); // 缩放,设置为不能缩放可以防止页面上出现放大和缩小的图标 settings.setBuiltInZoomControls(false); // 缓存 settings.setCacheMode(WebSettings.LOAD_DEFAULT); // 开启DOM storage API功能 settings.setDomStorageEnabled(true); // 开启application Cache功能 settings.setAppCacheEnabled(true); // 判断是否为无图模式 settings.setBlockNetworkImage(SettingUtil.getInstance().getIsNoPhotoMode()); // 不调用第三方浏览器即可进行页面反应 webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (!TextUtils.isEmpty(url)) { view.loadUrl(url); } return true; } @Override public void onPageFinished(WebView view, String url) { onHideLoading(); super.onPageFinished(view, url); } }); webView.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View view, int i, KeyEvent keyEvent) { if ((keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } return false; } }); webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); if (newProgress >= 90) { onHideLoading(); } else { onShowLoading(); } } }); } @Override public void onSetWebView(String url, boolean flag) { // 是否为头条的网站 if (flag) { webView.loadDataWithBaseURL(null, url, "text/html", "utf-8", null); } else { /* ScrollView 嵌套 WebView, 导致部分网页无法正常加载 如:https://temai.snssdk.com/article/feed/index/?id=11754971 最佳做法是去掉 ScrollView, 或使用 NestedScrollWebView */ if (shareUrl.contains("temai.snssdk.com")) { webView.getSettings().setUserAgentString(Constant.USER_AGENT_PC); } webView.loadUrl(shareUrl); } } @Override public void onShowNetError() { Snackbar.make(scrollView, R.string.network_error, Snackbar.LENGTH_INDEFINITE).show(); } @Override public void setPresenter(INewsContent.Presenter presenter) { if (null == presenter) { this.presenter = new NewsContentPresenter(this); } } @Override public void onShowLoading() { progressBar.show(); } @Override public void onHideLoading() { progressBar.hide(); swipeRefreshLayout.post(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(false); } }); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_browser, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_open_comment: // NewsCommentActivity.launch(bean.getGroup_id() + "", bean.getItem_id() + ""); break; case R.id.action_share: IntentAction.send(getActivity(), shareTitle + "\n" + shareUrl); break; case R.id.action_open_in_browser: startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(shareUrl))); break; case android.R.id.home: getActivity().onBackPressed(); break; case R.id.action_open_media_home: // MediaHomeActivity.launch(mediaId); break; } return super.onOptionsItemSelected(item); } }
3.2.一个新建片段实例,供外部调用。
==>返回一个片段Fragment。
3.3.决定两种布局。
一种是外部布局没有图片==>fragment_news_content.xml。
一种是外部布局有图片的==>fragment_news_content_img.xml。
fragment_news_content.xml源代码:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/news_content_main" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical"> <include layout="@layout/toolbar"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fadeScrollbars="true" android:scrollbarFadeDuration="1" android:scrollbars="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.NestedScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="16dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="16dp" android:background="@color/windowBackground"/> </android.support.v4.widget.NestedScrollView> </android.support.v4.widget.SwipeRefreshLayout> <android.support.v4.widget.ContentLoadingProgressBar android:id="@+id/pb_progress" style="?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout> </android.support.design.widget.CoordinatorLayout>
页面预览:
fragment_news_content_img.xml
<?xml version="1.0" encoding="utf-8"?> <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:id="@+id/news_content_main" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="192dp" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways"> <ImageView android:id="@+id/iv_image" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:minHeight="192dp" android:scaleType="centerCrop" android:scrollbarAlwaysDrawVerticalTrack="true" android:scrollbarStyle="insideInset" android:src="@mipmap/error_image" tools:ignore="ContentDescription"/> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fadeScrollbars="true" android:scrollbarFadeDuration="1" android:scrollbars="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.NestedScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="16dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="16dp" android:background="@color/windowBackground"/> </android.support.v4.widget.NestedScrollView> </android.support.v4.widget.SwipeRefreshLayout> <android.support.v4.widget.ContentLoadingProgressBar android:id="@+id/pb_progress" style="?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout> </android.support.design.widget.CoordinatorLayout>