让任意view具有滑动效果的SlideUp

贲招
2023-12-01
[img]http://dl2.iteye.com/upload/attachment/0122/1970/2255b23a-80f0-3c31-85e4-3186cd664982.gif[/img]

基本的类,只有一个:

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;

public class SlideUp implements View.OnTouchListener, ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
private View view;
private float touchableTop;
private int autoSlideDuration = 300;
private SlideListener slideListener;

private ValueAnimator valueAnimator;
private float slideAnimationTo;

private float startPositionY;
private float viewStartPositionY;
private boolean canSlide = true;
private float density;
private float lowerPosition;
private float viewHeight;

private boolean hiddenInit;

public SlideUp(final View view) {
this.view = view;
this.density = view.getResources().getDisplayMetrics().density;
this.touchableTop = 300 * density;
view.setOnTouchListener(this);
view.setPivotY(0);
createAnimation();
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (hiddenInit)
{
viewHeight = view.getHeight();
hideImmediately();
}
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}

public boolean isVisible(){
return view.getVisibility() == View.VISIBLE;
}

public void setSlideListener(SlideListener slideListener) {
this.slideListener = slideListener;
}

public void setAutoSlideDuration(int autoSlideDuration) {
this.autoSlideDuration = autoSlideDuration;
}

public float getAutoSlideDuration(){
return this.autoSlideDuration;
}

public void setTouchableTop(float touchableTop) {
this.touchableTop = touchableTop * density;
}

public float getTouchableTop() {
return this.touchableTop/density;
}

public boolean isAnimationRunning(){
return valueAnimator != null && valueAnimator.isRunning();
}

public void animateIn(){
this.slideAnimationTo = 0;
valueAnimator.setFloatValues(viewHeight, slideAnimationTo);
valueAnimator.start();
}

public void animateOut(){
this.slideAnimationTo = view.getHeight();
valueAnimator.setFloatValues(view.getTranslationY(), slideAnimationTo);
valueAnimator.start();
}

public void hideImmediately() {
if (view.getHeight() > 0)
{
view.setTranslationY(viewHeight);
view.setVisibility(View.GONE);
notifyVisibilityChanged(View.GONE);
}
else {
hiddenInit = true;
}
}

private void createAnimation(){
valueAnimator = ValueAnimator.ofFloat();
valueAnimator.setDuration(autoSlideDuration);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(this);
valueAnimator.addListener(this);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
float touchedArea = event.getRawY() - view.getTop();
if (isAnimationRunning())
{
return false;
}
switch (event.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
this.viewHeight = view.getHeight();
startPositionY = event.getRawY();
viewStartPositionY = view.getTranslationY();
if (touchableTop < touchedArea)
{
canSlide = false;
}
break;
case MotionEvent.ACTION_MOVE:
float difference = event.getRawY() - startPositionY;
float moveTo = viewStartPositionY + difference;
float percents = moveTo * 100 / view.getHeight();

if (moveTo > 0 && canSlide){
notifyPercentChanged(percents);
view.setTranslationY(moveTo);
}
if (event.getRawY() > lowerPosition)
{
lowerPosition = event.getRawY();
}
break;
case MotionEvent.ACTION_UP:
float slideAnimationFrom = view.getTranslationY();
boolean mustSlideUp = lowerPosition > event.getRawY();
boolean scrollableAreaConsumed = view.getTranslationY() > view.getHeight() / 5;

if (scrollableAreaConsumed && !mustSlideUp)
{
slideAnimationTo = view.getHeight();
}
else {
slideAnimationTo = 0;
}
valueAnimator.setFloatValues(slideAnimationFrom, slideAnimationTo);
valueAnimator.start();
canSlide = true;
lowerPosition = 0;
break;
}
return true;
}

@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
view.setTranslationY(val);
float percents = (view.getY() - view.getTop()) * 100 / viewHeight;
notifyPercentChanged(percents);
}

private void notifyPercentChanged(float percent){
if (slideListener != null)
{
slideListener.onSlide(percent);
}
}

private void notifyVisibilityChanged(int visibility){
if (slideListener != null)
{
slideListener.onVisibilityChanged(visibility);
}
}

@Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);
notifyVisibilityChanged(View.VISIBLE);
}

@Override
public void onAnimationEnd(Animator animator) {
if (slideAnimationTo > 0)
{
view.setVisibility(View.GONE);
notifyVisibilityChanged(View.GONE);
}
}

@Override
public void onAnimationCancel(Animator animator) {

}

@Override
public void onAnimationRepeat(Animator animator) {

}

public interface SlideListener {
void onSlide(float percent);
void onVisibilityChanged(int visibility);
}

}



基本用法:
创建一个任意类型的布局
<LinearLayout
android:id="@+id/slideView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

获取这个view,SlideUp对象并传入view
View slideView = findViewById(R.id.slideView);
SlideUp slideUp = new SlideUp(slideView);

更复杂的例子:

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import com.mancj.slideup.SlideUp;

public class SlideUpViewActivity extends AppCompatActivity {
private SlideUp slideUp;
private View dim;
private View slideView;
private FloatingActionButton fab;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_slide_up_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

slideView = findViewById(R.id.slideView);
dim = findViewById(R.id.dim);
fab = (FloatingActionButton) findViewById(R.id.fab);

slideUp = new SlideUp(slideView);
slideUp.hideImmediately();

fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
slideUp.animateIn();
fab.hide();
}
});

slideUp.setSlideListener(new SlideUp.SlideListener() {
@Override
public void onSlide(float percent) {
dim.setAlpha(1 - (percent / 100));
}

@Override
public void onVisibilityChanged(int visibility) {
if (visibility == View.GONE)
{
fab.show();
}
}
});

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_slide_up_view, menu);
return true;
}
}


布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:background="@color/colorPrimary">

<FrameLayout
android:alpha="0"
android:id="@+id/dim"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dimBg" />

<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.slideup.SlideUpViewActivity">

<android.support.design.widget.AppBarLayout
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
app:elevation="0dp"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_slide_up_view" />

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_call_black_24dp"
app:fabSize="normal" />

</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>

 类似资料: