Hide or show search bar while recycler view scroll

This commit is contained in:
seven332 committed 2015-04-29 13:34:26 +08:00
1 parent 894cf61d67
commit 00189740b2
5 files changed
+300 -15

No files matched your search

@@ -15,25 +15,34 @@
package com.hippo.ehviewer.ui.scene;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import com.hippo.animation.SimpleAnimatorListener;
import com.hippo.effect.ViewTransition;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.ehviewer.widget.ContentLayout;
import com.hippo.ehviewer.widget.OffsetLayout;
import com.hippo.ehviewer.widget.SearchBar;
import com.hippo.ehviewer.widget.SearchDatabase;
import com.hippo.ehviewer.widget.SearchLayout;
import com.hippo.scene.Scene;
import com.hippo.util.Log;
import com.hippo.util.MathUtils;
import com.hippo.util.ViewUtils;
public
class GalleryListScene extends Scene implements SearchBar.Helper {
private static final long ANIMATE_TIME = 300l;
private final static int STATE_NORMAL = 0;
private final static int STATE_SIMPLE_SEARCH = 1;
private final static int STATE_SEARCH = 2;
@@ -45,10 +54,16 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
private SearchBar mSearchBar;
private ContentLayout mContentLayout;
private RecyclerView mContentRecyclerView;
private SearchLayout mSearchLayout;
private RecyclerView mSearchRecyclerView;
private ViewTransition mViewTransition;
private int mSearchBarOriginalTop;
private int mSearchBarOriginalBottom;
private ValueAnimator mSearchBarMoveAnimator;
private int mState = STATE_NORMAL;
@Override
@@ -62,18 +77,28 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
mSearchBar = (SearchBar) findViewById(R.id.search_bar);
mContentLayout = (ContentLayout) findViewById(R.id.content_layout);
mContentRecyclerView = mContentLayout.getRecyclerView();
mSearchLayout = (SearchLayout) findViewById(R.id.search_layout);
mSearchRecyclerView = mSearchLayout.getRecyclerView();
mViewTransition = new ViewTransition(mContentLayout, mSearchLayout);
// Search Bar
mSearchBar.setHelper(this);
ViewUtils.measureView(mSearchBar, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
// Search Layout
mSearchLayout.setFitPaddingTop(mSearchBar.getMeasuredHeight() +
mResources.getDimensionPixelOffset(R.dimen.search_bar_padding_vertical));
ViewUtils.measureView(mSearchBar, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
SearchBarMoveHelper sbmHelper = new SearchBarMoveHelper();
mContentRecyclerView.addOnScrollListener(sbmHelper);
mSearchRecyclerView.addOnScrollListener(sbmHelper);
mSearchBar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewUtils.removeOnGlobalLayoutListener(mSearchBar.getViewTreeObserver(), this);
mSearchBarOriginalTop = mSearchBar.getTop();
mSearchBarOriginalBottom = mSearchBar.getBottom();
mSearchLayout.setFitPaddingTop(mSearchBar.getHeight() +
mResources.getDimensionPixelOffset(R.dimen.search_bar_padding_vertical));
}
});
// TEST
mContentLayout.showText("四姑拉斯基");
@@ -91,17 +116,20 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
super.onBackPressed();
break;
case STATE_SIMPLE_SEARCH:
mSearchBar.setInNormalMode();
mState = STATE_NORMAL;
mSearchBar.setInNormalMode();
returnSearchBarPosition();
break;
case STATE_SEARCH:
mState = STATE_NORMAL;
mViewTransition.showFirstView();
mSearchBar.setInNormalMode();
mState = STATE_NORMAL;
returnSearchBarPosition();
break;
case STATE_SEARCH_SHOW_LIST:
mSearchBar.hideImeAndSuggestionsList();
mState = STATE_SEARCH;
mSearchBar.hideImeAndSuggestionsList();
returnSearchBarPosition();
break;
}
}
@@ -111,6 +139,7 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
if (mState == STATE_NORMAL) {
mState = STATE_SIMPLE_SEARCH;
mSearchBar.setInEditMode(true);
returnSearchBarPosition();
}
}
@@ -127,18 +156,20 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
@Override
public void onClickAdvanceSearch() {
if (mState == STATE_NORMAL) {
mState = STATE_SEARCH;
mViewTransition.showSecondView();
mSearchLayout.scrollSearchContainerToTop();
mSearchBar.setInEditMode(false);
mState = STATE_SEARCH;
returnSearchBarPosition();
}
}
@Override
public void onSearchEditTextClick() {
if (mState == STATE_SEARCH) {
mSearchBar.showImeAndSuggestionsList();
mState = STATE_SEARCH_SHOW_LIST;
mSearchBar.showImeAndSuggestionsList();
returnSearchBarPosition();
}
}
@@ -147,8 +178,95 @@ class GalleryListScene extends Scene implements SearchBar.Helper {
Log.d("onApplySearch " + query);
mSearchDatabase.addQuery(query);
mState = STATE_NORMAL;
mViewTransition.showFirstView();
mSearchBar.setInNormalMode();
mState = STATE_NORMAL;
returnSearchBarPosition();
}
private RecyclerView getVaildRecyclerView() {
if (mState == STATE_NORMAL || mState == STATE_SIMPLE_SEARCH) {
return mContentRecyclerView;
} else {
return mSearchRecyclerView;
}
}
private void returnSearchBarPosition() {
boolean show;
if (mState == STATE_SIMPLE_SEARCH || mState == STATE_SEARCH_SHOW_LIST) {
show = true;
} else {
RecyclerView recyclerView = getVaildRecyclerView();
if (!recyclerView.isShown()) {
show = true;
} else if (recyclerView.computeVerticalScrollOffset() < mSearchBarOriginalBottom){
show = true;
} else if (mSearchBar.getBottom() > (mSearchBarOriginalBottom - mSearchBarOriginalTop) / 2) {
show = true;
} else {
show = false;
}
}
int offset;
if (show) {
offset = mSearchBarOriginalTop - mSearchBar.getTop();
} else {
offset = -mSearchBar.getBottom();
}
if (offset != 0) {
final ValueAnimator va = ValueAnimator.ofInt(0, offset);
va.setDuration(ANIMATE_TIME);
va.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
mSearchBarMoveAnimator = null;
}
});
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int lastValue;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
int offsetStep = value - lastValue;
lastValue = value;
mSearchBar.offsetTopAndBottom(offsetStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetStep;
}
});
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
mSearchBarMoveAnimator = va;
va.start();
}
}
private class SearchBarMoveHelper extends RecyclerView.OnScrollListener {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState){
if (newState == RecyclerView.SCROLL_STATE_IDLE && isVaildView(recyclerView)) {
returnSearchBarPosition();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (mState != STATE_SIMPLE_SEARCH && mState != STATE_SEARCH_SHOW_LIST &&
isVaildView(recyclerView)) {
int offsetYStep = MathUtils.clamp(-dy,
-mSearchBar.getBottom(), mSearchBarOriginalTop - mSearchBar.getTop());
mSearchBar.offsetTopAndBottom(offsetYStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetYStep;
}
}
private boolean isVaildView(RecyclerView view) {
return (mState == STATE_NORMAL && view == mContentRecyclerView) ||
(mState == STATE_SEARCH && view == mSearchRecyclerView);
}
}
}
@@ -40,6 +40,7 @@ public class ContentLayout extends FrameLayout {
private ProgressBar mProgressBar;
private ViewGroup mItView;
private RefreshLayout mRefreshLayout;
private EasyRecyclerView mRecyclerView;
private View mImageView;
private TextView mTextView;
@@ -64,10 +65,15 @@ public class ContentLayout extends FrameLayout {
mProgressBar = (ProgressBar) getChildAt(0);
mItView = (ViewGroup) getChildAt(1);
mRefreshLayout = (RefreshLayout) getChildAt(2);
mRecyclerView = (EasyRecyclerView) mRefreshLayout.getChildAt(1);
mImageView = mItView.getChildAt(0);
mTextView = (TextView) mItView.getChildAt(1);
}
public EasyRecyclerView getRecyclerView() {
return mRecyclerView;
}
public void showProgressBar() {
ViewUtils.setVisibility(mProgressBar, View.VISIBLE);
ViewUtils.setVisibility(mItView, View.GONE);
@@ -0,0 +1,153 @@
/*
* 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.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
public class OffsetLayout extends FrameLayout {
public OffsetLayout(Context context) {
super(context);
}
public OffsetLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OffsetLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildrenEx(left, top, right, bottom, false /* no force left gravity */);
}
// TODO foreground not work fine
@SuppressLint("RtlHardcoded")
void layoutChildrenEx(int left, int top, int right, int bottom,
boolean forceLeftGravity) {
final int count = getChildCount();
final int parentLeft = getPaddingLeft();
final int parentRight = right - left - getPaddingRight();
final int parentTop = getPaddingTop();
final int parentBottom = bottom - top - getPaddingBottom();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = Gravity.TOP | Gravity.LEFT;
}
final int absoluteGravity = gravity;
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
if (!forceLeftGravity) {
childLeft = parentRight - width - lp.rightMargin;
break;
}
case Gravity.LEFT:
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
child.layout(childLeft + lp.offsetX, childTop + lp.offsetY,
childLeft + width + lp.offsetX, childTop + height + lp.offsetY);
}
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
public static class LayoutParams extends FrameLayout.LayoutParams {
public int offsetX;
public int offsetY;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
public LayoutParams(FrameLayout.LayoutParams source) {
super((ViewGroup.MarginLayoutParams) source);
this.gravity = source.gravity;
}
public LayoutParams(int width, int height) {
super(width, height);
}
}
}
@@ -159,8 +159,16 @@ public class SearchLayout extends FrameLayout implements CompoundButton.OnChecke
mSearchPaddingBottomOrigin);
}
public EasyRecyclerView getRecyclerView() {
return mSearchContainer;
}
public void setFitPaddingTop(int fitPaddingTop) {
mSearchContainer.setPadding(mSearchContainer.getPaddingLeft(), mSearchPaddingTopOrigin + fitPaddingTop, mSearchContainer.getPaddingRight(), mSearchContainer.getPaddingBottom());
mSearchContainer.setPadding(
mSearchContainer.getPaddingLeft(),
mSearchPaddingTopOrigin + fitPaddingTop,
mSearchContainer.getPaddingRight(),
mSearchContainer.getPaddingBottom());
}
public void setFitPaddingBottom(int fitPaddingBottom) {