package com.looklook.xinghongfei.looklook.activity; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.graphics.Bitmap; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.content.ContextCompat; import android.support.v4.widget.NestedScrollView; import android.support.v7.graphics.Palette; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.transition.ChangeBounds; import android.transition.Transition; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.liuguangqiang.swipeback.SwipeBackActivity; import com.liuguangqiang.swipeback.SwipeBackLayout; import com.looklook.xinghongfei.looklook.R; import com.looklook.xinghongfei.looklook.bean.zhihu.ZhihuStory; import com.looklook.xinghongfei.looklook.config.Config; import com.looklook.xinghongfei.looklook.presenter.IZhihuStoryPresenter; import com.looklook.xinghongfei.looklook.presenter.implPresenter.ZhihuStoryPresenterImpl; import com.looklook.xinghongfei.looklook.presenter.implView.IZhihuStory; import com.looklook.xinghongfei.looklook.util.AnimUtils; import com.looklook.xinghongfei.looklook.util.ColorUtils; import com.looklook.xinghongfei.looklook.util.DensityUtil; import com.looklook.xinghongfei.looklook.util.GlideUtils; import com.looklook.xinghongfei.looklook.util.ViewUtils; import com.looklook.xinghongfei.looklook.util.WebUtil; import com.looklook.xinghongfei.looklook.widget.ElasticDragDismissFrameLayout; import com.looklook.xinghongfei.looklook.widget.ParallaxScrimageView; import com.looklook.xinghongfei.looklook.widget.TranslateYTextView; import java.lang.reflect.InvocationTargetException; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; /** * Created by xinghongfei on 16/8/13. */ public class ZhihuDescribeActivity extends SwipeBackActivity implements IZhihuStory { private static final float SCRIM_ADJUSTMENT = 0.075f; @BindView(R.id.shot) ParallaxScrimageView mShot; @Nullable @BindView(R.id.toolbar) Toolbar mToolbar; @BindView(R.id.wv_zhihu) WebView wvZhihu; @BindView(R.id.nest) NestedScrollView mNest; @BindView(R.id.title) TranslateYTextView mTranslateYTextView; boolean isEmpty; String mBody; String[] scc; String mImageUrl; // @BindView(R.id.draggable_frame) // ElasticDragDismissFrameLayout mDraggableFrame; int[] mDeviceInfo; int width; int heigh; private Transition.TransitionListener zhihuReturnHomeListener; private NestedScrollView.OnScrollChangeListener scrollListener; private String id; private String title; private String url; private IZhihuStoryPresenter mIZhihuStoryPresenter; private ElasticDragDismissFrameLayout.SystemChromeFader chromeFader; private Handler mHandler=new Handler(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.zhihudescribe); setDragEdge(SwipeBackLayout.DragEdge.LEFT); ButterKnife.bind(this); mDeviceInfo = DensityUtil.getDeviceInfo(this); width = mDeviceInfo[0]; heigh = width * 3 / 4; setSupportActionBar(mToolbar); initlistenr(); initData(); initView(); getData(); chromeFader = new ElasticDragDismissFrameLayout.SystemChromeFader(this); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ getWindow().getSharedElementReturnTransition().addListener(zhihuReturnHomeListener); getWindow().setSharedElementEnterTransition(new ChangeBounds()); } enterAnimation(); } private void initlistenr() { zhihuReturnHomeListener = new AnimUtils.TransitionListenerAdapter() { @Override public void onTransitionStart(Transition transition) { super.onTransitionStart(transition); // hide the fab as for some reason it jumps position?? TODO work out why mToolbar.animate() .alpha(0f) .setDuration(100) .setInterpolator(new AccelerateInterpolator()); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { mShot.setElevation(1f); mToolbar.setElevation(0f); } mNest.animate() .alpha(0f) .setDuration(50) .setInterpolator(new AccelerateInterpolator()); } }; scrollListener = new NestedScrollView.OnScrollChangeListener() { @Override public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { if (oldScrollY<168){ mShot.setOffset(-oldScrollY); mTranslateYTextView.setOffset(-oldScrollY); } } }; } protected void initData() { id = getIntent().getStringExtra("id"); title = getIntent().getStringExtra("title"); mImageUrl = getIntent().getStringExtra("image"); mIZhihuStoryPresenter = new ZhihuStoryPresenterImpl(this); mNest.setOnScrollChangeListener(scrollListener); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ postponeEnterTransition(); mShot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mShot.getViewTreeObserver().removeOnPreDrawListener(this); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { startPostponedEnterTransition(); } return true; } }); } } private void initView() { mToolbar.setTitleMargin(20,20,0,10); mToolbar.setNavigationIcon(R.drawable.ic_arrow_back); mToolbar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mNest.smoothScrollTo(0,0); } }); mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { expandImageAndFinish(); } }); mTranslateYTextView.setText(title); WebSettings settings = wvZhihu.getSettings(); settings.setJavaScriptEnabled(true); settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); settings.setLoadWithOverviewMode(true); settings.setBuiltInZoomControls(true); //settings.setUseWideViewPort(true);造成文字太小 settings.setDomStorageEnabled(true); settings.setDatabaseEnabled(true); settings.setAppCachePath(getCacheDir().getAbsolutePath() + "/webViewCache"); settings.setAppCacheEnabled(true); settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); wvZhihu.setWebChromeClient(new WebChromeClient()); } @Override protected void onResume() { super.onResume(); // mDraggableFrame.addListener(chromeFader); try { wvZhihu.getClass().getMethod("onResume").invoke(wvZhihu, (Object[]) null); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } @Override protected void onPause() { super.onPause(); // mDraggableFrame.removeListener(chromeFader); try { wvZhihu.getClass().getMethod("onPause").invoke(wvZhihu, (Object[]) null); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } @Override protected void onDestroy() { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { getWindow().getSharedElementReturnTransition().removeListener(zhihuReturnHomeListener); } //webview内存泄露 if (wvZhihu != null) { ((ViewGroup) wvZhihu.getParent()).removeView(wvZhihu); wvZhihu.destroy(); wvZhihu = null; } mIZhihuStoryPresenter.unsubscrible(); super.onDestroy(); } @Override public void onBackPressed() { super.onBackPressed(); expandImageAndFinish(); } private void getData() { mIZhihuStoryPresenter.getZhihuStory(id); } @OnClick(R.id.shot) public void onClick() { mNest.smoothScrollTo(0, 0); } @Override public void showError(String error) { Snackbar.make(wvZhihu, getString(R.string.snack_infor), Snackbar.LENGTH_INDEFINITE).setAction("重试", new View.OnClickListener() { @Override public void onClick(View v) { getData(); } }).show(); } @Override public void showZhihuStory(ZhihuStory zhihuStory) { Glide.with(this) .load(zhihuStory.getImage()).centerCrop() .listener(loadListener).override(width,heigh) .diskCacheStrategy(DiskCacheStrategy.SOURCE) .into(mShot); url = zhihuStory.getShareUrl(); isEmpty=TextUtils.isEmpty(zhihuStory.getBody()); mBody=zhihuStory.getBody(); scc=zhihuStory.getCss(); if (isEmpty) { wvZhihu.loadUrl(url); } else { String data = WebUtil.buildHtmlWithCss(mBody, scc, Config.isNight); wvZhihu.loadDataWithBaseURL(WebUtil.BASE_URL, data, WebUtil.MIME_TYPE, WebUtil.ENCODING, WebUtil.FAIL_URL); } } private void expandImageAndFinish() { if (mShot.getOffset() != 0f) { Animator expandImage = ObjectAnimator.ofFloat(mShot, ParallaxScrimageView.OFFSET, 0f); expandImage.setDuration(80); expandImage.setInterpolator(new AccelerateInterpolator()); expandImage.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { finishAfterTransition(); }else { finish(); } } }); expandImage.start(); } else { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { finishAfterTransition(); }else { finish(); } } } private RequestListener loadListener = new RequestListener<String, GlideDrawable>() { @Override public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { final Bitmap bitmap = GlideUtils.getBitmap(resource); final int twentyFourDip = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, ZhihuDescribeActivity.this.getResources().getDisplayMetrics()); Palette.from(bitmap) .maximumColorCount(3) .clearFilters() /* by default palette ignore certain hues (e.g. pure black/white) but we don't want this. */ .setRegion(0, 0, bitmap.getWidth() - 1, twentyFourDip) /* - 1 to work around https://code.google.com/p/android/issues/detail?id=191013 */ .generate(new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { boolean isDark; @ColorUtils.Lightness int lightness = ColorUtils.isDark(palette); if (lightness == ColorUtils.LIGHTNESS_UNKNOWN) { isDark = ColorUtils.isDark(bitmap, bitmap.getWidth() / 2, 0); } else { isDark = lightness == ColorUtils.IS_DARK; } // color the status bar. Set a complementary dark color on L, // light or dark color on M (with matching status bar icons) if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ int statusBarColor = getWindow().getStatusBarColor(); final Palette.Swatch topColor = ColorUtils.getMostPopulousSwatch(palette); if (topColor != null && (isDark || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)) { statusBarColor = ColorUtils.scrimify(topColor.getRgb(), isDark, SCRIM_ADJUSTMENT); // set a light status bar on M+ if (!isDark && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ViewUtils.setLightStatusBar(mShot); } } if (statusBarColor != getWindow().getStatusBarColor()) { mShot.setScrimColor(statusBarColor); ValueAnimator statusBarColorAnim = ValueAnimator.ofArgb( getWindow().getStatusBarColor(), statusBarColor); statusBarColorAnim.addUpdateListener(new ValueAnimator .AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { getWindow().setStatusBarColor( (int) animation.getAnimatedValue()); } }); statusBarColorAnim.setDuration(1000L); statusBarColorAnim.setInterpolator( new AccelerateInterpolator()); statusBarColorAnim.start(); } } } }); Palette.from(bitmap) .clearFilters() .generate(new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { // slightly more opaque ripple on the pinned image to compensate // for the scrim if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ mShot.setForeground(ViewUtils.createRipple(palette, 0.3f, 0.6f, ContextCompat.getColor(ZhihuDescribeActivity.this, R.color.mid_grey), true)); } } }); // TODO should keep the background if the image contains transparency?! mShot.setBackground(null); return false; } @Override public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) { return false; } }; private void enterAnimation() { float offSet = mToolbar.getHeight(); LinearInterpolator interpolator=new LinearInterpolator(); viewEnterAnimation(mShot, offSet, interpolator); viewEnterAnimationNest(mNest,0f,interpolator); } private void viewEnterAnimation(View view, float offset, Interpolator interp) { view.setTranslationY(-offset); view.setAlpha(0f); view.animate() .translationY(0f) .alpha(1f) .setDuration(500L) .setInterpolator(interp) .setListener(null) .start(); } private void viewEnterAnimationNest(View view, float offset, Interpolator interp) { view.setTranslationY(-offset); view.setAlpha(0.3f); view.animate() .translationY(0f) .alpha(1f) .setDuration(500L) .setInterpolator(interp) .setListener(null) .start(); } }