package com.joker.rxweather.views.activity; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Intent; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.CoordinatorLayout; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import butterknife.Bind; import butterknife.OnClick; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.joker.rxweather.MyApplication; import com.joker.rxweather.R; import com.joker.rxweather.adapter.DetailAdapter; import com.joker.rxweather.common.Constants; import com.joker.rxweather.common.Utils; import com.joker.rxweather.common.rx.rxbus.RxBus; import com.joker.rxweather.model.entities.ForecastWeatherEntity; import com.joker.rxweather.model.entities.MainEntity; import com.joker.rxweather.model.entities.WeatherEntity; import com.joker.rxweather.ui.InsertDecoration; import com.trello.rxlifecycle.ActivityEvent; import java.util.List; import rx.Observable; import rx.functions.Action1; import rx.subscriptions.CompositeSubscription; /** * Created by Joker on 2015/11/3. */ public class DetailActivity extends BaseActivity { private static final String TAG = DetailActivity.class.getSimpleName(); private static final String START_BOUND = "START_BOUND"; private static final String FINAL_BOUND = "FINAL_BOUND"; private static final String SCALE = "SCALE"; private static int orientation = -1; @Nullable @Bind(R.id.detail_layout_root_view) FrameLayout rootView; @Nullable @Bind(R.id.detail_layout_container) CoordinatorLayout container; @Nullable @Bind(R.id.detail_layout_weather_tv) TextView weatherTv; @Nullable @Bind(R.id.detail_layout_weather_iv) ImageView weatherIv; @Nullable @Bind(R.id.detail_layout_suggest_tv) TextView suggestTv; @Nullable @Bind(R.id.detail_layout_rv) RecyclerView recyclerView; @Nullable @Bind(R.id.detail_layout_anim_iv) ImageView animIv; private Rect startBounds; private Rect finalBounds = new Rect(); private float scale; private AnimatorSet animatorSet; private MainEntity mainEntity; private WeatherEntity weatherEntity; private List<ForecastWeatherEntity> forecastWeatherEntities; private DetailAdapter detailAdapter; private CompositeSubscription compositeSubscription = new CompositeSubscription(); private RxBus rxBus; private boolean cancelBack = false; private int x; public static void navigateToDetail(AppCompatActivity startingActivity, Rect startBounds, Point globalOffset) { Intent intent = new Intent(startingActivity, DetailActivity.class); intent.putExtra(Constants.POINT, globalOffset).putExtra(Constants.RECT, startBounds); startingActivity.startActivity(intent); } @Override protected int getLayoutId() { return R.layout.detail_layout; } @Override protected void onCreated() { if (DetailActivity.orientation == -1) { DetailActivity.orientation = getResources().getConfiguration().orientation; } if (rxBus == null) rxBus = MyApplication.get().getRxBus(); /*按理说,任何一个粘性事件都不应该持有相应的Observable*/ if (!rxBus.hasStickObservers() && mainEntity == null) { DetailActivity.this.getData(); } } @SuppressWarnings("unchecked") private void getData() { this.compositeSubscription.add(MyApplication .get() .getRxBus() .toStickObservable(MainEntity.class) .compose(DetailActivity.this.<MainEntity>bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Action1<MainEntity>() { @Override public void call(MainEntity mainEntity) { DetailActivity.this.mainEntity = mainEntity; weatherEntity = mainEntity.getWeatherEntity(); forecastWeatherEntities = mainEntity.getForecastWeatherEntityList(); } })); } @Override protected void initView(Bundle savedInstanceState) { DetailActivity.this.setupAnimIv(); DetailActivity.this.setupAdapter(); if (savedInstanceState == null) { rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { rootView.getViewTreeObserver().removeOnPreDrawListener(this); DetailActivity.this.runEnterAnimation(getIntent().getExtras()); return true; } }); } else { DetailActivity.this.startBounds = savedInstanceState.getParcelable(START_BOUND); DetailActivity.this.finalBounds = savedInstanceState.getParcelable(FINAL_BOUND); DetailActivity.this.scale = savedInstanceState.getFloat(SCALE); ViewCompat.setPivotX(animIv, 0.0f); ViewCompat.setPivotY(animIv, 0.0f); ViewCompat.setTranslationX(animIv, finalBounds.left); ViewCompat.setTranslationY(animIv, finalBounds.top); DetailActivity.this.initData(); this.compositeSubscription.add(Observable.just(forecastWeatherEntities).subscribe(detailAdapter)); } } private void setupAdapter() { LinearLayoutManager linearLayoutManager = new LinearLayoutManager(DetailActivity.this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); linearLayoutManager.setSmoothScrollbarEnabled(true); detailAdapter = new DetailAdapter(DetailActivity.this); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setHasFixedSize(true); recyclerView.setAdapter(detailAdapter); recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); recyclerView.addItemDecoration(new InsertDecoration(DetailActivity.this)); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mainEntity != null) { outState.putSerializable(Constants.CACHE, mainEntity); outState.putParcelable(START_BOUND, startBounds); outState.putParcelable(FINAL_BOUND, finalBounds); outState.putFloat(SCALE, scale); } } private void runEnterAnimation(Bundle extras) { if (animatorSet != null) animatorSet.cancel(); ViewCompat.setAlpha(container, 0.0f); Point globalOffset = extras.getParcelable(Constants.POINT); startBounds = extras.getParcelable(Constants.RECT); weatherIv.getGlobalVisibleRect(finalBounds); finalBounds.offset(-globalOffset.x, -globalOffset.y); scale = Utils.calculateScale(startBounds, finalBounds); this.animIv.setVisibility(View.VISIBLE); this.animIv.setLayerType(View.LAYER_TYPE_HARDWARE, null); ViewCompat.setPivotX(animIv, 0.0f); ViewCompat.setPivotY(animIv, 0.0f); AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(this.animIv, View.X, startBounds.left, finalBounds.left)) .with(ObjectAnimator.ofFloat(this.animIv, View.Y, startBounds.top, finalBounds.top)) .with(ObjectAnimator.ofFloat(this.animIv, View.SCALE_X, scale, 1.0f)) .with(ObjectAnimator.ofFloat(this.animIv, View.SCALE_Y, scale, 1.0f)) .with(ObjectAnimator.ofFloat(this.animIv, View.ALPHA, 0.4f, 1.0f)); set.setDuration(Constants.MILLISECONDS_300); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animIv.setLayerType(View.LAYER_TYPE_NONE, null); animIv.setVisibility(View.GONE); if (DetailActivity.this.animatorSet != null) DetailActivity.this.initData(); DetailActivity.this.animatorSet = null; } @Override public void onAnimationCancel(Animator animation) { DetailActivity.this.animatorSet = null; } }); set.start(); DetailActivity.this.animatorSet = set; } private void setupAnimIv() { Glide .with(DetailActivity.this) .load(Constants.ICON_URL + weatherEntity.weatherCode + ".png") .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.RESULT) .into(animIv); } private void initData() { ViewCompat.setAlpha(container, 1.0f); weatherTv.setText(weatherEntity.cityName); suggestTv.setText(weatherEntity.drsgDescription); Glide .with(MyApplication.get()) .load(Constants.ICON_URL + weatherEntity.weatherCode + ".png") .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.RESULT) .into(weatherIv); this.compositeSubscription.add(Observable.just(forecastWeatherEntities).subscribe(detailAdapter)); } @Override protected void exit() { if (DetailActivity.orientation == getResources().getConfiguration().orientation) { if (cancelBack) return; if (animatorSet != null) animatorSet.cancel(); ViewCompat.animate(container).alpha(0.0f); this.animIv.setVisibility(View.VISIBLE); this.animIv.setLayerType(View.LAYER_TYPE_HARDWARE, null); AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(this.animIv, View.X, startBounds.left)) .with(ObjectAnimator.ofFloat(this.animIv, View.Y, startBounds.top)) .with(ObjectAnimator.ofFloat(this.animIv, View.SCALE_X, scale)) .with(ObjectAnimator.ofFloat(this.animIv, View.SCALE_Y, scale)) .with(ObjectAnimator.ofFloat(this.animIv, View.ALPHA, 0.1f)); set.setDuration(Constants.MILLISECONDS_300); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { DetailActivity.this.animatorSet = null; animIv.setLayerType(View.LAYER_TYPE_NONE, null); DetailActivity.this.finish(); overridePendingTransition(0, 0); } @Override public void onAnimationCancel(Animator animation) { DetailActivity.this.cancelBack = true; DetailActivity.this.animatorSet = null; } }); set.start(); DetailActivity.this.animatorSet = set; } else { ViewCompat .animate(rootView) .translationY(Utils.getScreenHeight(DetailActivity.this)) .setDuration(Constants.MILLISECONDS_300) .setInterpolator(new DecelerateInterpolator()) .withLayer() .setListener(new ViewPropertyAnimatorListenerAdapter() { @Override public void onAnimationEnd(View view) { DetailActivity.this.finish(); overridePendingTransition(0, 0); } }); } } @OnClick(R.id.detail_layout_fv) void onForkViewClick() { /*thanks for helping,http://www.jianshu.com/p/eaae783b931f*/ Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri content_url = Uri.parse(Constants.J_URL); intent.setData(content_url); if (intent.resolveActivity(getPackageManager()) != null) { DetailActivity.this.startActivity(intent); } } @Override protected void onDestroy() { if (this.compositeSubscription.hasSubscriptions()) this.compositeSubscription.clear(); super.onDestroy(); if (isFinishing()) DetailActivity.orientation = -1; } }