Improve view state saving

This commit is contained in:
seven332 committed 2015-05-06 10:37:48 +08:00
1 parent 5da51bd984
commit a20565f1b2
8 files changed
+237 -234

No files matched your search

@@ -15,6 +15,7 @@
package com.hippo.drawable;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -24,6 +25,7 @@ import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import com.hippo.ehviewer.R;
import com.hippo.util.MathUtils;
@@ -181,4 +183,28 @@ public class DrawerArrowDrawable extends Drawable {
mProgress = progress;
invalidateSelf();
}
public void setMenu(long duration) {
setShape(false, duration);
}
public void setArrow(long duration) {
setShape(true, duration);
}
public void setShape(boolean arrow, long duration) {
if (!((!arrow && mProgress == 0f) || (arrow && mProgress == 1f))) {
float endProgress = arrow ? 1f : 0f;
if (duration <= 0) {
setProgress(endProgress);
} else {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "progress", endProgress);
oa.setDuration(duration);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa.setAutoCancel(true);
}
oa.start();
}
}
}
}
@@ -49,60 +49,78 @@ public class ViewTransition {
}
public void showFirstView() {
showFirstView(true);
}
public void showFirstView(boolean animation) {
if (mSwitch) {
mSwitch = false;
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 0f, 1f);
oa1.setDuration(ANIMATE_TIME);
oa1.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
ViewUtils.setVisibility(mView1, View.VISIBLE);
if (animation) {
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 0f, 1f);
oa1.setDuration(ANIMATE_TIME);
oa1.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
ViewUtils.setVisibility(mView1, View.VISIBLE);
}
});
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 1f, 0f);
oa2.setDuration(ANIMATE_TIME);
oa2.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
ViewUtils.setVisibility(mView2, View.GONE);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
oa2.setAutoCancel(true);
}
});
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 1f, 0f);
oa2.setDuration(ANIMATE_TIME);
oa2.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
ViewUtils.setVisibility(mView2, View.GONE);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
oa2.setAutoCancel(true);
oa1.start();
oa2.start();
} else {
ViewUtils.setVisibility(mView1, View.VISIBLE);
ViewUtils.setVisibility(mView2, View.GONE);
}
oa1.start();
oa2.start();
}
}
public void showSecondView() {
showSecondView(true);
}
public void showSecondView(boolean animation) {
if (!mSwitch) {
mSwitch = true;
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 1f, 0f);
oa1.setDuration(ANIMATE_TIME);
oa1.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
ViewUtils.setVisibility(mView1, View.GONE);
if (animation) {
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 1f, 0f);
oa1.setDuration(ANIMATE_TIME);
oa1.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
ViewUtils.setVisibility(mView1, View.GONE);
}
});
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 0f, 1f);
oa2.setDuration(ANIMATE_TIME);
oa2.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
ViewUtils.setVisibility(mView2, View.VISIBLE);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
oa2.setAutoCancel(true);
}
});
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 0f, 1f);
oa2.setDuration(ANIMATE_TIME);
oa2.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
ViewUtils.setVisibility(mView2, View.VISIBLE);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
oa2.setAutoCancel(true);
oa1.start();
oa2.start();
} else {
ViewUtils.setVisibility(mView1, View.GONE);
ViewUtils.setVisibility(mView2, View.VISIBLE);
}
oa1.start();
oa2.start();
}
}
}
@@ -22,9 +22,12 @@ import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -127,6 +130,12 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
mSearchBarOriginalTop = mSearchBar.getTop();
mSearchBarOriginalBottom = mSearchBar.getBottom();
mSearchLayout.setFitPaddingTop(mSearchBar.getHeight() + mResources.getDimensionPixelOffset(R.dimen.search_bar_padding_vertical));
Log.d("mSearchBarOriginalTop = " + mSearchBarOriginalTop);
Log.d("mSearchBarOriginalBottom = " + mSearchBarOriginalBottom);
}
});
mSearchLayout.setHelper(this);
@@ -150,6 +159,32 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
mContentLayout.showText("四姑拉斯基");
}
@Override
protected void onRestoreInstanceState(@NonNull SparseArray<Parcelable> savedStates) {
super.onRestoreInstanceState(savedStates);
switch (mState) {
case STATE_NORMAL:
case STATE_SIMPLE_SEARCH:
mViewTransition.showFirstView(false);
break;
case STATE_SEARCH:
case STATE_SEARCH_SHOW_LIST:
mViewTransition.showSecondView(false);
break;
}
// Restore Fab drawable
if (mFabState == FAB_STATE_NORMAL) {
mAddDeleteDrawable.setShape(mFabLayout.isExpanded(), 0);
mCornerFab.setDrawable(mAddDeleteDrawable);
} else if (mFabState == FAB_STATE_SEARCH) {
mCornerFab.setDrawable(mSearchDrawable);
}
// Do not keep search bar position, keep it shown
}
@Override
protected void onGetFitPaddingBottom(int b) {
// Search Layout
@@ -193,7 +228,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
public void onBackPressed() {
switch (mState) {
case STATE_NORMAL:
if (mFabLayout.getExpanded()) {
if (mFabLayout.isExpanded()) {
mFabLayout.setExpanded(false);
mAddDeleteDrawable.setShape(false, ANIMATE_TIME);
} else {
@@ -202,20 +237,20 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
break;
case STATE_SIMPLE_SEARCH:
mState = STATE_NORMAL;
mSearchBar.setInNormalMode();
mSearchBar.setState(SearchBar.STATE_NORMAL);
returnSearchBarPosition();
setFabState(FAB_STATE_NORMAL);
break;
case STATE_SEARCH:
mState = STATE_NORMAL;
mViewTransition.showFirstView();
mSearchBar.setInNormalMode();
mSearchBar.setState(SearchBar.STATE_NORMAL);
returnSearchBarPosition();
setFabState(FAB_STATE_NORMAL);
break;
case STATE_SEARCH_SHOW_LIST:
mState = STATE_SEARCH;
mSearchBar.hideImeAndSuggestionsList();
mSearchBar.setState(SearchBar.STATE_SEARCH);
returnSearchBarPosition();
break;
}
@@ -223,7 +258,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
private void toggleFabLayout() {
mFabLayout.toggle();
mAddDeleteDrawable.setShape(mFabLayout.getExpanded(), ANIMATE_TIME);
mAddDeleteDrawable.setShape(mFabLayout.isExpanded(), ANIMATE_TIME);
}
@Override
@@ -252,7 +287,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
public void onClickTitle() {
if (mState == STATE_NORMAL) {
mState = STATE_SIMPLE_SEARCH;
mSearchBar.setInEditMode(true);
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST);
returnSearchBarPosition();
setFabState(FAB_STATE_SEARCH);
}
@@ -274,7 +309,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
mState = STATE_SEARCH;
mViewTransition.showSecondView();
mSearchLayout.scrollSearchContainerToTop();
mSearchBar.setInEditMode(false);
mSearchBar.setState(SearchBar.STATE_SEARCH);
returnSearchBarPosition();
setFabState(FAB_STATE_SEARCH);
}
@@ -284,7 +319,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
public void onSearchEditTextClick() {
if (mState == STATE_SEARCH) {
mState = STATE_SEARCH_SHOW_LIST;
mSearchBar.showImeAndSuggestionsList();
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST);
returnSearchBarPosition();
}
}
@@ -297,7 +332,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
mState = STATE_NORMAL;
mViewTransition.showFirstView();
mSearchBar.setInNormalMode();
mSearchBar.setState(SearchBar.STATE_NORMAL);
returnSearchBarPosition();
setFabState(FAB_STATE_NORMAL);
}
@@ -423,10 +458,19 @@ public class GalleryListScene extends Scene implements SearchBar.Helper,
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (mState != STATE_SIMPLE_SEARCH && mState != STATE_SEARCH_SHOW_LIST &&
isVaildView(recyclerView)) {
int oldBottom = mSearchBar.getBottom();
int offsetYStep = MathUtils.clamp(-dy,
-mSearchBar.getBottom(), mSearchBarOriginalTop - mSearchBar.getTop());
mSearchBar.offsetTopAndBottom(offsetYStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetYStep;
int newBottom = mSearchBar.getBottom();
// TODO Sometimes if it is out of screen than go into again, it do not show,
// so I need to requestLayout
if (oldBottom == 0 && newBottom > 0) {
mSearchBar.requestLayout();
}
}
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.scene;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.scene.Scene;
public class TestScene extends Scene {
private ContentActivity mActivity;
private Resources mResources;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scene_test);
mActivity = (ContentActivity) getStageActivity();
mResources = mActivity.getResources();
}
}
@@ -24,6 +24,8 @@ import android.graphics.Color;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.text.Editable;
@@ -35,6 +37,7 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
@@ -44,6 +47,7 @@ import android.widget.TextView;
import com.hippo.animation.SimpleAnimatorListener;
import com.hippo.drawable.AddDeleteDrawable;
import com.hippo.drawable.DrawerArrowDrawable;
import com.hippo.effect.ViewTransition;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
@@ -61,8 +65,17 @@ public class SearchBar extends CardView implements View.OnClickListener,
TextView.OnEditorActionListener, TextWatcher,
SearchEditText.SearchEditTextListener, Messenger.Receiver {
private static final String STATE_KEY_SUPER = "super";
private static final String STATE_KEY_STATE = "state";
private static final long ANIMATE_TIME = 300l;
public static final int STATE_NORMAL = 0;
public static final int STATE_SEARCH = 1;
public static final int STATE_SEARCH_LIST = 2;
private int mState = STATE_NORMAL;
private Path mPath = new Path();
private int mWidth;
private int mHeight;
@@ -75,6 +88,8 @@ public class SearchBar extends CardView implements View.OnClickListener,
private SearchEditText mEditText;
private ListView mList;
private ViewTransition mViewTransition;
private DrawerArrowDrawable mDrawerArrowDrawable;
private AddDeleteDrawable mAddDeleteDrawable;
@@ -84,9 +99,7 @@ public class SearchBar extends CardView implements View.OnClickListener,
private Helper mHelper;
private boolean mInEditMode = false;
private boolean mInAnimation = false;
private boolean mFirstLayout = true;
private int mSource;
@@ -119,6 +132,8 @@ public class SearchBar extends CardView implements View.OnClickListener,
mEditText = (SearchEditText) findViewById(R.id.search_edit_text);
mList = (ListView) findViewById(R.id.search_bar_list);
mViewTransition = new ViewTransition(mTitleTextView, mEditText);
mDrawerArrowDrawable = new DrawerArrowDrawable(getContext());
mAddDeleteDrawable = new AddDeleteDrawable(getContext());
@@ -131,6 +146,11 @@ public class SearchBar extends CardView implements View.OnClickListener,
mEditText.setOnEditorActionListener(this);
mEditText.addTextChangedListener(this);
// Get base height
ViewUtils.measureView(this, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mBaseHeight = getMeasuredHeight();
mSuggestionList = new ArrayList<>();
// TODO
mSuggestionAdapter = new ArrayAdapter<>(getContext(),
@@ -191,16 +211,16 @@ public class SearchBar extends CardView implements View.OnClickListener,
if (v == mTitleTextView) {
mHelper.onClickTitle();
} else if (v == mMenuButton) {
if (mInEditMode) {
mHelper.onClickArrow();
} else {
if (mState == STATE_NORMAL) {
mHelper.onClickMenu();
} else {
mHelper.onClickArrow();
}
} else if (v == mActionButton) {
if (mInEditMode) {
mEditText.setText("");
} else {
if (mState == STATE_NORMAL) {
mHelper.onClickAdvanceSearch();
} else {
mEditText.setText("");
}
}
}
@@ -217,75 +237,60 @@ public class SearchBar extends CardView implements View.OnClickListener,
return false;
}
public void setInEditMode(boolean showList) {
if (!mInEditMode) {
mInEditMode = true;
setClickable(false);
ViewUtils.setVisibility(mTitleTextView, View.GONE);
ViewUtils.setVisibility(mEditText, View.VISIBLE);
mEditText.requestFocus();
// start animator
if (mDrawerArrowDrawable.getProgress() != 1f) {
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mDrawerArrowDrawable, "progress", 0f, 1f);
oa1.setDuration(ANIMATE_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
}
oa1.start();
}
if (mAddDeleteDrawable.getProgress() != 1f) {
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mAddDeleteDrawable, "progress", 0f, 1f);
oa2.setDuration(ANIMATE_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa2.setAutoCancel(true);
}
oa2.start();
}
// Show list if needed
if (showList) {
showImeAndSuggestionsList();
public void setState(int state) {
setState(state, true);
}
public void setState(int state, boolean animation) {
if (mState != state) {
int oldState = mState;
mState = state;
switch (oldState) {
default:
case STATE_NORMAL:
mViewTransition.showSecondView(animation);
mEditText.requestFocus();
mDrawerArrowDrawable.setArrow(animation ? ANIMATE_TIME : 0);
mAddDeleteDrawable.setDelete(animation ? ANIMATE_TIME : 0);
if (state == STATE_SEARCH_LIST) {
showImeAndSuggestionsList(animation);
}
break;
case STATE_SEARCH:
if (state == STATE_NORMAL) {
mViewTransition.showFirstView(animation);
mDrawerArrowDrawable.setMenu(animation ? ANIMATE_TIME : 0);
mAddDeleteDrawable.setAdd(animation ? ANIMATE_TIME : 0);
} else if (state == STATE_SEARCH_LIST) {
showImeAndSuggestionsList(animation);
}
break;
case STATE_SEARCH_LIST:
hideImeAndSuggestionsList(animation);
if (state == STATE_NORMAL) {
mViewTransition.showFirstView(animation);
mDrawerArrowDrawable.setMenu(animation ? ANIMATE_TIME : 0);
mAddDeleteDrawable.setAdd(animation ? ANIMATE_TIME : 0);
}
break;
}
}
}
public void setInNormalMode() {
if (mInEditMode) {
mInEditMode = false;
setOnClickListener(this);
ViewUtils.setVisibility(mTitleTextView, View.VISIBLE);
ViewUtils.setVisibility(mEditText, View.GONE);
// start animator
if (mDrawerArrowDrawable.getProgress() != 0f) {
ObjectAnimator oa1 = ObjectAnimator.ofFloat(mDrawerArrowDrawable, "progress", 1f, 0f);
oa1.setDuration(ANIMATE_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa1.setAutoCancel(true);
}
oa1.start();
}
if (mAddDeleteDrawable.getProgress() != 0f) {
ObjectAnimator oa2 = ObjectAnimator.ofFloat(mAddDeleteDrawable, "progress", 1f, 0f);
oa2.setDuration(ANIMATE_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
oa2.setAutoCancel(true);
}
oa2.start();
}
// Hide ime and suggestions list
hideImeAndSuggestionsList();
}
private void showImeAndSuggestionsList() {
showImeAndSuggestionsList(true);
}
public void showImeAndSuggestionsList() {
private void showImeAndSuggestionsList(boolean animation) {
// Show ime
mEditText.requestFocus();
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mEditText, 0);
// update suggestion for show suggestions list
updateSuggestions();
// Show suggestions list
if (mProgress != 1f) {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "progress", 0f, 1f);
if (animation) {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "progress", 1f);
oa.setDuration(ANIMATE_TIME);
oa.addListener(new SimpleAnimatorListener() {
@Override
@@ -303,16 +308,22 @@ public class SearchBar extends CardView implements View.OnClickListener,
oa.setAutoCancel(true);
}
oa.start();
} else {
setProgress(1f);
}
}
public void hideImeAndSuggestionsList() {
private void hideImeAndSuggestionsList() {
hideImeAndSuggestionsList(true);
}
private void hideImeAndSuggestionsList(boolean animation) {
// Hide ime
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
// Hide suggestions list
if (mProgress != 0f) {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "progress", 1f, 0f);
if (animation) {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "progress", 0f);
oa.setDuration(ANIMATE_TIME);
oa.addListener(new SimpleAnimatorListener() {
@Override
@@ -330,6 +341,8 @@ public class SearchBar extends CardView implements View.OnClickListener,
oa.setAutoCancel(true);
}
oa.start();
} else {
setProgress(0f);
}
}
@@ -340,14 +353,10 @@ public class SearchBar extends CardView implements View.OnClickListener,
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mInEditMode) {
if (mList.getVisibility() == View.VISIBLE) {
mWidth = right - left;
mHeight = bottom - top;
}
if (mFirstLayout) {
mFirstLayout = false;
mBaseHeight = bottom - top;
}
}
@SuppressWarnings("unused")
@@ -411,6 +420,23 @@ public class SearchBar extends CardView implements View.OnClickListener,
}
}
@Override
public Parcelable onSaveInstanceState() {
final Bundle state = new Bundle();
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
state.putInt(STATE_KEY_STATE, mState);
return state;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
final Bundle savedState = (Bundle) state;
super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
setState(savedState.getInt(STATE_KEY_STATE), false);
}
}
public interface Helper {
void onClickTitle();
void onClickMenu();
@@ -221,7 +221,7 @@ public class FabLayout extends ViewGroup implements View.OnClickListener {
setExpanded(!mExpanded);
}
public boolean getExpanded() {
public boolean isExpanded() {
return mExpanded;
}