/*
* Copyright 2016 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
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.widget;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.SimpleAnimatorListener;
import com.hippo.yorozuya.ViewUtils;
public class SearchBarMover extends RecyclerView.OnScrollListener {
private static final long ANIMATE_TIME = 300L;
private boolean mShow;
private ValueAnimator mSearchBarMoveAnimator;
private final Helper mHelper;
private final View mSearchBar;
public SearchBarMover(Helper helper, View searchBar, RecyclerView... recyclerViews) {
mHelper = helper;
mSearchBar = searchBar;
for (RecyclerView recyclerView: recyclerViews) {
recyclerView.addOnScrollListener(this);
}
}
public void cancelAnimation() {
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState){
if (newState == RecyclerView.SCROLL_STATE_IDLE && mHelper.isValidView(recyclerView)) {
returnSearchBarPosition();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (mHelper.isValidView(recyclerView)) {
int oldBottom = (int) ViewUtils.getY2(mSearchBar);
int offsetYStep = MathUtils.clamp(-dy, -oldBottom, -(int) mSearchBar.getTranslationY());
if (offsetYStep != 0) {
ViewUtils.translationYBy(mSearchBar, offsetYStep);
}
}
}
public void returnSearchBarPosition() {
returnSearchBarPosition(true);
}
@SuppressWarnings("SimplifiableIfStatement")
public void returnSearchBarPosition(boolean animation) {
if (mSearchBar.getHeight() == 0) {
// Layout not called
return;
}
boolean show;
if (mHelper.forceShowSearchBar()) {
show = true;
} else {
RecyclerView recyclerView = mHelper.getValidRecyclerView();
if (recyclerView == null) {
return;
}
if (!recyclerView.isShown()) {
show = true;
} else if (recyclerView.computeVerticalScrollOffset() < mSearchBar.getBottom()){
show = true;
} else {
show = (int) ViewUtils.getY2(mSearchBar) > (mSearchBar.getHeight()) / 2;
}
}
int offset;
if (show) {
offset = -(int) mSearchBar.getTranslationY();
} else {
offset = -(int) ViewUtils.getY2(mSearchBar);
}
if (offset == 0) {
// No need to scroll
return;
}
if (animation) {
if (mSearchBarMoveAnimator != null) {
if (mShow == show) {
// The same target, no need to do animation
return;
} else {
// Cancel it
mSearchBarMoveAnimator.cancel();
mSearchBarMoveAnimator = null;
}
}
mShow = show;
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;
ViewUtils.translationYBy(mSearchBar, offsetStep);
}
});
mSearchBarMoveAnimator = va;
va.start();
} else {
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
ViewUtils.translationYBy(mSearchBar, offset);
}
}
public void showSearchBar() {
showSearchBar(true);
}
public void showSearchBar(boolean animation) {
if (mSearchBar.getHeight() == 0) {
// Layout not called
return;
}
final int offset = -(int) mSearchBar.getTranslationY();
if (offset == 0) {
// No need to scroll
return;
}
if (animation) {
if (mSearchBarMoveAnimator != null) {
if (mShow) {
// The same target, no need to do animation
return;
} else {
// Cancel it
mSearchBarMoveAnimator.cancel();
mSearchBarMoveAnimator = null;
}
}
mShow = true;
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;
ViewUtils.translationYBy(mSearchBar, offsetStep);
}
});
mSearchBarMoveAnimator = va;
va.start();
} else {
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
ViewUtils.translationYBy(mSearchBar, offset);
}
}
public interface Helper {
boolean isValidView(RecyclerView recyclerView);
@Nullable
RecyclerView getValidRecyclerView();
boolean forceShowSearchBar();
}
}