Android仿高德首页三段式滑动

最近发现很多app都使用了三段式滑动,比如说高德的首页和某宝等物流信息都是使用的三段式滑动方式,谷歌其实给了我们很好的2段式滑动,就是BottomSheet,所以这次我也是在这个原理基础上做了一个小小的修改来实现我们今天想要的效果。

高德的效果

实现的效果

我们实现的效果和高德差距不是很大,也很顺滑。具体实现其实就是集成CoordinatorLayout.Behavior

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.zwl.mybehaviordemo.gaode;import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.annotation.VisibleForTesting;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.coordinatorlayout.widget.CoordinatorLayout.Behavior;
import androidx.core.math.MathUtils;
import androidx.core.view.ViewCompat;
import androidx.customview.view.AbsSavedState;
import androidx.customview.widget.ViewDragHelper;
import androidx.customview.widget.ViewDragHelper.Callback;import com.zwl.mybehaviordemo.R;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;/*** 高德首页滑动效果** @author yixiaolunhui*/
public class GaoDeBottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {public static final int STATE_DRAGGING = 1;public static final int STATE_SETTLING = 2;public static final int STATE_EXPANDED = 3;public static final int STATE_COLLAPSED = 4;public static final int STATE_HIDDEN = 5;public static final int STATE_HALF_EXPANDED = 6;public static final int PEEK_HEIGHT_AUTO = -1;private static final float HIDE_THRESHOLD = 0.5F;private static final float HIDE_FRICTION = 0.1F;public static final int MIDDLE_HEIGHT_AUTO = -1;private boolean fitToContents = true;private float maximumVelocity;private int peekHeight;private boolean peekHeightAuto;private int peekHeightMin;private int lastPeekHeight;int fitToContentsOffset;int halfExpandedOffset;int collapsedOffset;boolean hideable;private boolean skipCollapsed;int state = STATE_COLLAPSED;ViewDragHelper viewDragHelper;private boolean ignoreEvents;private int lastNestedScrollDy;private boolean nestedScrolled;int parentHeight;WeakReference<V> viewRef;WeakReference<View> nestedScrollingChildRef;private GaoDeBottomSheetBehavior.BottomSheetCallback callback;private VelocityTracker velocityTracker;int activePointerId;private int initialY;boolean touchingScrollingChild;private Map<View, Integer> importantForAccessibilityMap;private final Callback dragCallback;private int mMiddleHeight;private boolean mMiddleHeightAuto;public GaoDeBottomSheetBehavior() {this.dragCallback = new NamelessClass_1();}public GaoDeBottomSheetBehavior(Context context, AttributeSet attrs) {super(context, attrs);this.dragCallback = new NamelessClass_1();TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BottomSheetBehavior_Layout);TypedValue value = a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight);if (value != null && value.data == -1) {this.setPeekHeight(value.data);} else {this.setPeekHeight(a.getDimensionPixelSize(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, -1));}this.setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideAble, false));this.setFitToContents(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_fitToContents, true));this.setSkipCollapsed(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapse, false));setMiddleHeight(a.getDimensionPixelSize(R.styleable.BottomSheetBehavior_Layout_behavior_middleHeight, MIDDLE_HEIGHT_AUTO));a.recycle();ViewConfiguration configuration = ViewConfiguration.get(context);this.maximumVelocity = (float) configuration.getScaledMaximumFlingVelocity();}class NamelessClass_1 extends Callback {NamelessClass_1() {}@Overridepublic boolean tryCaptureView(@NonNull View child, int pointerId) {if (GaoDeBottomSheetBehavior.this.state == STATE_DRAGGING) {return false;} else if (GaoDeBottomSheetBehavior.this.touchingScrollingChild) {return false;} else {if (GaoDeBottomSheetBehavior.this.state == 3 && GaoDeBottomSheetBehavior.this.activePointerId == pointerId) {View scroll = (View) GaoDeBottomSheetBehavior.this.nestedScrollingChildRef.get();if (scroll != null && scroll.canScrollVertically(-1)) {return false;}}return GaoDeBottomSheetBehavior.this.viewRef != null && GaoDeBottomSheetBehavior.this.viewRef.get() == child;}}@Overridepublic void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {GaoDeBottomSheetBehavior.this.dispatchOnSlide(top);}@Overridepublic void onViewDragStateChanged(int state) {if (state == 1) {GaoDeBottomSheetBehavior.this.setStateInternal(STATE_DRAGGING);}}@Overridepublic void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {int top;byte targetState;int currentTop;if (yvel < 0.0F) {if (GaoDeBottomSheetBehavior.this.fitToContents) {currentTop = releasedChild.getTop();if (currentTop < (collapsedOffset + HIDE_THRESHOLD) && currentTop >= halfExpandedOffset) {top = GaoDeBottomSheetBehavior.this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = GaoDeBottomSheetBehavior.this.fitToContentsOffset;targetState = STATE_EXPANDED;}} else {currentTop = releasedChild.getTop();if (currentTop > GaoDeBottomSheetBehavior.this.halfExpandedOffset) {top = GaoDeBottomSheetBehavior.this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = 0;targetState = STATE_EXPANDED;}}} else if (!GaoDeBottomSheetBehavior.this.hideable || !GaoDeBottomSheetBehavior.this.shouldHide(releasedChild, yvel) || releasedChild.getTop() <= GaoDeBottomSheetBehavior.this.collapsedOffset && Math.abs(xvel) >= Math.abs(yvel)) {if (yvel != 0.0F && Math.abs(xvel) <= Math.abs(yvel)) {currentTop = releasedChild.getTop();if (currentTop < halfExpandedOffset) {top = GaoDeBottomSheetBehavior.this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = GaoDeBottomSheetBehavior.this.collapsedOffset;targetState = STATE_COLLAPSED;}} else {currentTop = releasedChild.getTop();if (GaoDeBottomSheetBehavior.this.fitToContents) {if (Math.abs(currentTop - GaoDeBottomSheetBehavior.this.fitToContentsOffset) < Math.abs(currentTop - GaoDeBottomSheetBehavior.this.collapsedOffset)) {top = GaoDeBottomSheetBehavior.this.fitToContentsOffset;targetState = STATE_EXPANDED;} else {top = GaoDeBottomSheetBehavior.this.collapsedOffset;targetState = STATE_COLLAPSED;}} else if (currentTop < GaoDeBottomSheetBehavior.this.halfExpandedOffset) {if (currentTop < Math.abs(currentTop - GaoDeBottomSheetBehavior.this.collapsedOffset)) {top = 0;targetState = STATE_EXPANDED;} else {top = GaoDeBottomSheetBehavior.this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;}} else if (Math.abs(currentTop - GaoDeBottomSheetBehavior.this.halfExpandedOffset) < Math.abs(currentTop - GaoDeBottomSheetBehavior.this.collapsedOffset)) {top = GaoDeBottomSheetBehavior.this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = GaoDeBottomSheetBehavior.this.collapsedOffset;targetState = STATE_COLLAPSED;}}} else {top = GaoDeBottomSheetBehavior.this.parentHeight;targetState = STATE_HIDDEN;}if (GaoDeBottomSheetBehavior.this.viewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {GaoDeBottomSheetBehavior.this.setStateInternal(STATE_SETTLING);ViewCompat.postOnAnimation(releasedChild, GaoDeBottomSheetBehavior.this.new SettleRunnable(releasedChild, targetState));} else {GaoDeBottomSheetBehavior.this.setStateInternal(targetState);}}@Overridepublic int clampViewPositionVertical(@NonNull View child, int top, int dy) {return MathUtils.clamp(top, GaoDeBottomSheetBehavior.this.getExpandedOffset(), GaoDeBottomSheetBehavior.this.hideable ? GaoDeBottomSheetBehavior.this.parentHeight : GaoDeBottomSheetBehavior.this.collapsedOffset);}@Overridepublic int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {return child.getLeft();}@Overridepublic int getViewVerticalDragRange(@NonNull View child) {return GaoDeBottomSheetBehavior.this.hideable ? GaoDeBottomSheetBehavior.this.parentHeight : GaoDeBottomSheetBehavior.this.collapsedOffset;}}@Overridepublic Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {return new GaoDeBottomSheetBehavior.SavedState(super.onSaveInstanceState(parent, child), this.state);}@Overridepublic void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {GaoDeBottomSheetBehavior.SavedState ss = (GaoDeBottomSheetBehavior.SavedState) state;super.onRestoreInstanceState(parent, child, ss.getSuperState());if (ss.state != STATE_DRAGGING && ss.state != STATE_SETTLING) {this.state = ss.state;} else {this.state = STATE_COLLAPSED;}}@Overridepublic boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {child.setFitsSystemWindows(true);}int savedTop = child.getTop();parent.onLayoutChild(child, layoutDirection);this.parentHeight = parent.getHeight();if (this.peekHeightAuto) {if (this.peekHeightMin == 0) {this.peekHeightMin = parent.getResources().getDimensionPixelSize(R.dimen.design_bottom_sheet_peek_height_min);}this.lastPeekHeight = Math.max(this.peekHeightMin, this.parentHeight - parent.getWidth() * 9 / 16);} else {this.lastPeekHeight = this.peekHeight;}if (mMiddleHeightAuto) {mMiddleHeight = this.parentHeight;}this.fitToContentsOffset = Math.max(0, this.parentHeight - child.getHeight());this.halfExpandedOffset = this.parentHeight - mMiddleHeight;this.calculateCollapsedOffset();if (this.state == STATE_EXPANDED) {ViewCompat.offsetTopAndBottom(child, this.getExpandedOffset());} else if (this.state == STATE_HALF_EXPANDED) {ViewCompat.offsetTopAndBottom(child, this.halfExpandedOffset);} else if (this.hideable && this.state == STATE_HIDDEN) {ViewCompat.offsetTopAndBottom(child, this.parentHeight);} else if (this.state == STATE_COLLAPSED) {ViewCompat.offsetTopAndBottom(child, this.collapsedOffset);} else if (this.state == STATE_DRAGGING || this.state == STATE_SETTLING) {ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());}if (this.viewDragHelper == null) {this.viewDragHelper = ViewDragHelper.create(parent, this.dragCallback);}this.viewRef = new WeakReference(child);this.nestedScrollingChildRef = new WeakReference(this.findScrollingChild(child));return true;}@Overridepublic boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {if (!child.isShown()) {this.ignoreEvents = true;return false;} else {int action = event.getActionMasked();if (action == 0) {this.reset();}if (this.velocityTracker == null) {this.velocityTracker = VelocityTracker.obtain();}this.velocityTracker.addMovement(event);switch (action) {case 0:int initialX = (int) event.getX();this.initialY = (int) event.getY();View scroll = this.nestedScrollingChildRef != null ? (View) this.nestedScrollingChildRef.get() : null;if (scroll != null && parent.isPointInChildBounds(scroll, initialX, this.initialY)) {this.activePointerId = event.getPointerId(event.getActionIndex());this.touchingScrollingChild = true;}this.ignoreEvents = this.activePointerId == -1 && !parent.isPointInChildBounds(child, initialX, this.initialY);break;case 1:case 3:this.touchingScrollingChild = false;this.activePointerId = -1;if (this.ignoreEvents) {this.ignoreEvents = false;return false;}case 2:}if (!this.ignoreEvents && this.viewDragHelper != null && this.viewDragHelper.shouldInterceptTouchEvent(event)) {return true;} else {View scroll = this.nestedScrollingChildRef != null ? (View) this.nestedScrollingChildRef.get() : null;return action == 2 && scroll != null && !this.ignoreEvents && this.state != 1 && !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) && this.viewDragHelper != null && Math.abs((float) this.initialY - event.getY()) > (float) this.viewDragHelper.getTouchSlop();}}}@Overridepublic boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {if (!child.isShown()) {return false;} else {int action = event.getActionMasked();if (this.state == STATE_DRAGGING && action == 0) {return true;} else {if (this.viewDragHelper != null) {this.viewDragHelper.processTouchEvent(event);}if (action == 0) {this.reset();}if (this.velocityTracker == null) {this.velocityTracker = VelocityTracker.obtain();}this.velocityTracker.addMovement(event);if (action == 2 && !this.ignoreEvents && Math.abs((float) this.initialY - event.getY()) > (float) this.viewDragHelper.getTouchSlop()) {this.viewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));}return !this.ignoreEvents;}}}@Overridepublic boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {this.lastNestedScrollDy = 0;this.nestedScrolled = false;return (axes & 2) != 0;}@Overridepublic void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {if (type != 1) {View scrollingChild = (View) this.nestedScrollingChildRef.get();if (target == scrollingChild) {int currentTop = child.getTop();int newTop = currentTop - dy;if (dy > 0) {if (newTop < this.getExpandedOffset()) {consumed[1] = currentTop - this.getExpandedOffset();ViewCompat.offsetTopAndBottom(child, -consumed[1]);this.setStateInternal(STATE_EXPANDED);} else {consumed[1] = dy;ViewCompat.offsetTopAndBottom(child, -dy);this.setStateInternal(STATE_DRAGGING);}} else if (dy < 0 && !target.canScrollVertically(-1)) {if (newTop > this.collapsedOffset && !this.hideable) {consumed[1] = currentTop - this.collapsedOffset;ViewCompat.offsetTopAndBottom(child, -consumed[1]);this.setStateInternal(STATE_COLLAPSED);} else {consumed[1] = dy;ViewCompat.offsetTopAndBottom(child, -dy);this.setStateInternal(STATE_DRAGGING);}}this.dispatchOnSlide(child.getTop());this.lastNestedScrollDy = dy;this.nestedScrolled = true;}}}@Overridepublic void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int type) {if (child.getTop() == this.getExpandedOffset()) {this.setStateInternal(STATE_EXPANDED);} else if (target == this.nestedScrollingChildRef.get() && this.nestedScrolled) {int top;byte targetState;if (this.lastNestedScrollDy > 0) {int currentTop = child.getTop();if (currentTop <= collapsedOffset - HIDE_THRESHOLD && currentTop >= halfExpandedOffset) {top = this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = this.getExpandedOffset();targetState = STATE_EXPANDED;}} else if (this.hideable && this.shouldHide(child, this.getYVelocity())) {top = this.parentHeight;targetState = STATE_HIDDEN;} else if (this.lastNestedScrollDy == 0) {int currentTop = child.getTop();if (this.fitToContents) {if (Math.abs(currentTop - this.fitToContentsOffset) < Math.abs(currentTop - this.collapsedOffset)) {top = this.fitToContentsOffset;targetState = STATE_EXPANDED;} else {top = this.collapsedOffset;targetState = STATE_COLLAPSED;}} else if (currentTop < this.halfExpandedOffset) {if (currentTop < Math.abs(currentTop - this.collapsedOffset)) {top = 0;targetState = STATE_EXPANDED;} else {top = this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;}} else if (Math.abs(currentTop - this.halfExpandedOffset) < Math.abs(currentTop - this.collapsedOffset)) {top = this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = this.collapsedOffset;targetState = STATE_COLLAPSED;}} else {int currentTop = child.getTop();if (currentTop <= halfExpandedOffset + HIDE_THRESHOLD && currentTop > HIDE_THRESHOLD) {top = this.halfExpandedOffset;targetState = STATE_HALF_EXPANDED;} else {top = this.collapsedOffset;targetState = STATE_COLLAPSED;}}if (this.viewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {this.setStateInternal(STATE_SETTLING);ViewCompat.postOnAnimation(child, new GaoDeBottomSheetBehavior.SettleRunnable(child, targetState));} else {this.setStateInternal(targetState);}this.nestedScrolled = false;}}@Overridepublic boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, float velocityX, float velocityY) {return target == this.nestedScrollingChildRef.get() && (this.state != STATE_EXPANDED || super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY));}public boolean isFitToContents() {return this.fitToContents;}public void setFitToContents(boolean fitToContents) {if (this.fitToContents != fitToContents) {this.fitToContents = fitToContents;if (this.viewRef != null) {this.calculateCollapsedOffset();}this.setStateInternal(this.fitToContents && this.state == STATE_HALF_EXPANDED ? STATE_HALF_EXPANDED : this.state);}}public final void setPeekHeight(int peekHeight) {boolean layout = false;if (peekHeight == -1) {if (!this.peekHeightAuto) {this.peekHeightAuto = true;layout = true;}} else if (this.peekHeightAuto || this.peekHeight != peekHeight) {this.peekHeightAuto = false;this.peekHeight = Math.max(0, peekHeight);this.collapsedOffset = this.parentHeight - peekHeight;layout = true;}if (layout && this.state == STATE_COLLAPSED && this.viewRef != null) {V view = (V) this.viewRef.get();if (view != null) {view.requestLayout();}}}public final void setMiddleHeight(int middleHeight) {boolean layout = false;if (middleHeight == PEEK_HEIGHT_AUTO) {if (!mMiddleHeightAuto) {mMiddleHeightAuto = true;layout = true;}} else if (mMiddleHeightAuto || mMiddleHeight != middleHeight) {mMiddleHeightAuto = false;mMiddleHeight = Math.max(0, middleHeight);layout = true;}if (layout && this.state == STATE_COLLAPSED && viewRef != null) {V view = viewRef.get();if (view != null) {view.requestLayout();}}}public final int getPeekHeight() {return this.peekHeightAuto ? -1 : this.peekHeight;}public final int getMiddleHeight() {return this.mMiddleHeightAuto ? -1 : this.mMiddleHeight;}public final int getParentHeight() {return this.parentHeight;}public void setHideable(boolean hideable) {this.hideable = hideable;}public boolean isHideable() {return this.hideable;}public void setSkipCollapsed(boolean skipCollapsed) {this.skipCollapsed = skipCollapsed;}public boolean getSkipCollapsed() {return this.skipCollapsed;}public void setBottomSheetCallback(GaoDeBottomSheetBehavior.BottomSheetCallback callback) {this.callback = callback;}public final void setState(final int state) {if (state != this.state) {if (this.viewRef == null) {if (state == STATE_COLLAPSED || state == STATE_EXPANDED || state == STATE_HALF_EXPANDED || this.hideable && state == STATE_HIDDEN) {this.state = state;}} else {final V child = (V) this.viewRef.get();if (child != null) {ViewParent parent = child.getParent();if (parent != null && parent.isLayoutRequested() && ViewCompat.isAttachedToWindow(child)) {child.post(new Runnable() {@Overridepublic void run() {GaoDeBottomSheetBehavior.this.startSettlingAnimation(child, state);}});} else {this.startSettlingAnimation(child, state);}}}}}public final int getState() {return this.state;}void setStateInternal(int state) {if (this.state != state) {this.state = state;if (state != STATE_HALF_EXPANDED && state != STATE_EXPANDED) {if (state == STATE_HIDDEN || state == STATE_COLLAPSED) {this.updateImportantForAccessibility(false);}} else {this.updateImportantForAccessibility(true);}View bottomSheet = (View) this.viewRef.get();if (bottomSheet != null && this.callback != null) {this.callback.onStateChanged(bottomSheet, state);}}}private void calculateCollapsedOffset() {if (this.fitToContents) {this.collapsedOffset = Math.max(this.parentHeight - this.lastPeekHeight, this.fitToContentsOffset);} else {this.collapsedOffset = this.parentHeight - this.lastPeekHeight;}}private void reset() {this.activePointerId = -1;if (this.velocityTracker != null) {this.velocityTracker.recycle();this.velocityTracker = null;}}boolean shouldHide(View child, float yvel) {if (this.skipCollapsed) {return true;} else if (child.getTop() < this.collapsedOffset) {return false;} else {float newTop = (float) child.getTop() + yvel * HIDE_FRICTION;return Math.abs(newTop - (float) this.collapsedOffset) / (float) this.peekHeight > HIDE_THRESHOLD;}}@VisibleForTestingView findScrollingChild(View view) {if (ViewCompat.isNestedScrollingEnabled(view)) {return view;} else {if (view instanceof ViewGroup) {ViewGroup group = (ViewGroup) view;int i = 0;for (int count = group.getChildCount(); i < count; ++i) {View scrollingChild = this.findScrollingChild(group.getChildAt(i));if (scrollingChild != null) {return scrollingChild;}}}return null;}}private float getYVelocity() {if (this.velocityTracker == null) {return 0.0F;} else {this.velocityTracker.computeCurrentVelocity(1000, this.maximumVelocity);return this.velocityTracker.getYVelocity(this.activePointerId);}}private int getExpandedOffset() {return this.fitToContents ? this.fitToContentsOffset : 0;}void startSettlingAnimation(View child, int state) {int top;if (state == STATE_COLLAPSED) {top = this.collapsedOffset;} else if (state == STATE_HALF_EXPANDED) {top = this.halfExpandedOffset;} else if (state == STATE_EXPANDED) {top = this.getExpandedOffset();} else {if (!this.hideable || state != STATE_HIDDEN) {throw new IllegalArgumentException("Illegal state argument: " + state);}top = this.parentHeight;}if (this.viewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {this.setStateInternal(STATE_SETTLING);ViewCompat.postOnAnimation(child, new GaoDeBottomSheetBehavior.SettleRunnable(child, state));} else {this.setStateInternal(state);}}void dispatchOnSlide(int top) {View bottomSheet = (View) this.viewRef.get();if (bottomSheet != null && this.callback != null) {if (top > this.collapsedOffset) {this.callback.onSlide(bottomSheet, (float) (this.collapsedOffset - top) / (float) (this.parentHeight - this.collapsedOffset));} else {this.callback.onSlide(bottomSheet, (float) (this.collapsedOffset - top) / (float) (this.collapsedOffset - this.getExpandedOffset()));}}}@VisibleForTestingint getPeekHeightMin() {return this.peekHeightMin;}public static <V extends View> GaoDeBottomSheetBehavior<V> from(V view) {LayoutParams params = view.getLayoutParams();if (!(params instanceof CoordinatorLayout.LayoutParams)) {throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");} else {Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior();if (!(behavior instanceof GaoDeBottomSheetBehavior)) {throw new IllegalArgumentException("The view is not associated with BottomSheetBehavior");} else {return (GaoDeBottomSheetBehavior) behavior;}}}@SuppressLint("WrongConstant")private void updateImportantForAccessibility(boolean expanded) {if (this.viewRef != null) {ViewParent viewParent = ((View) this.viewRef.get()).getParent();if (viewParent instanceof CoordinatorLayout) {CoordinatorLayout parent = (CoordinatorLayout) viewParent;int childCount = parent.getChildCount();if (VERSION.SDK_INT >= 16 && expanded) {if (this.importantForAccessibilityMap != null) {return;}this.importantForAccessibilityMap = new HashMap(childCount);}for (int i = 0; i < childCount; ++i) {View child = parent.getChildAt(i);if (child != this.viewRef.get()) {if (!expanded) {if (this.importantForAccessibilityMap != null && this.importantForAccessibilityMap.containsKey(child)) {ViewCompat.setImportantForAccessibility(child, (Integer) this.importantForAccessibilityMap.get(child));}} else {if (VERSION.SDK_INT >= 16) {this.importantForAccessibilityMap.put(child, child.getImportantForAccessibility());}ViewCompat.setImportantForAccessibility(child, 4);}}}if (!expanded) {this.importantForAccessibilityMap = null;}}}}protected static class SavedState extends AbsSavedState {final int state;public static final Creator<GaoDeBottomSheetBehavior.SavedState> CREATOR = new ClassLoaderCreator<GaoDeBottomSheetBehavior.SavedState>() {@Overridepublic GaoDeBottomSheetBehavior.SavedState createFromParcel(Parcel in, ClassLoader loader) {return new GaoDeBottomSheetBehavior.SavedState(in, loader);}@Overridepublic GaoDeBottomSheetBehavior.SavedState createFromParcel(Parcel in) {return new GaoDeBottomSheetBehavior.SavedState(in, (ClassLoader) null);}@Overridepublic GaoDeBottomSheetBehavior.SavedState[] newArray(int size) {return new GaoDeBottomSheetBehavior.SavedState[size];}};public SavedState(Parcel source) {this(source, (ClassLoader) null);}public SavedState(Parcel source, ClassLoader loader) {super(source, loader);this.state = source.readInt();}public SavedState(Parcelable superState, int state) {super(superState);this.state = state;}@Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeInt(this.state);}}private class SettleRunnable implements Runnable {private final View view;private final int targetState;SettleRunnable(View view, int targetState) {this.view = view;this.targetState = targetState;}@Overridepublic void run() {if (GaoDeBottomSheetBehavior.this.viewDragHelper != null && GaoDeBottomSheetBehavior.this.viewDragHelper.continueSettling(true)) {ViewCompat.postOnAnimation(this.view, this);} else {GaoDeBottomSheetBehavior.this.setStateInternal(this.targetState);}}}@Retention(RetentionPolicy.SOURCE)@RestrictTo({Scope.LIBRARY_GROUP})public @interface State {}public abstract static class BottomSheetCallback {public BottomSheetCallback() {}public abstract void onStateChanged(@NonNull View var1, int var2);public abstract void onSlide(@NonNull View var1, float var2);}
}

使用的时候直接设置

    <androidx.appcompat.widget.LinearLayoutCompatandroid:id="@+id/bottom_sheet"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"android:orientation="vertical"android:visibility="visible"app:behavior_hideable="false"app:behavior_middleHeight="200dp"app:behavior_peekHeight="80dp"app:layout_behavior=".gaode.GaoDeBottomSheetBehavior"tools:ignore="MissingPrefix">//....</androidx.appcompat.widget.LinearLayoutCompat>

对于按钮滑动及通明度渐变隐藏显示也是通过实现behavior,因为比较的简单直接上代码

package com.zwl.mybehaviordemo.gaode;import android.content.Context;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.NonNull;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;import com.zwl.mybehaviordemo.R;/*** 高德首页按钮处理** @author yixiaolunhui*/
public class GaoDeBtnBehavior extends CoordinatorLayout.Behavior {private View rightActions;private View topActions;public GaoDeBtnBehavior() {}public GaoDeBtnBehavior(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull View child, int layoutDirection) {if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {child.setFitsSystemWindows(true);}if (rightActions == null) {rightActions = parent.findViewById(R.id.rightActions);}if (topActions == null) {topActions = parent.findViewById(R.id.topActions);}return super.onLayoutChild(parent, child, layoutDirection);}@Overridepublic boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) {return dependency instanceof LinearLayoutCompat || super.layoutDependsOn(parent, child, dependency);}@Overridepublic boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) {//判断当前dependency 是内容布局if (dependency instanceof LinearLayoutCompat && dependency.getId() == R.id.bottom_sheet) {if (rightActions != null) {GaoDeBottomSheetBehavior behavior = GaoDeBottomSheetBehavior.from(dependency);int middleHeight = behavior.getParentHeight() - behavior.getMiddleHeight() - rightActions.getMeasuredHeight();CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) rightActions.getLayoutParams();int newY = dependency.getTop() - rightActions.getHeight() - layoutParams.bottomMargin;if (newY >= middleHeight) {rightActions.setTranslationY(newY - layoutParams.bottomMargin);} else {rightActions.setTranslationY(middleHeight);}int offset = behavior.getParentHeight() - behavior.getMiddleHeight() - layoutParams.bottomMargin - dependency.getTop();float alpha = 1f - offset * 1.0f / rightActions.getHeight();rightActions.setAlpha(alpha);if (topActions != null) {topActions.setAlpha(alpha);}}}return super.onDependentViewChanged(parent, child, dependency);}}

github:github.com/yixiaolunhui/FGaoDeIndexDemo
好了,话不多说,一笑轮回~~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/785457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刷题之动态规划-路径问题

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;开始刷动态规划的题目了&#xff0c;要特别注意初始化的时候给什么值。 动态规划5个步骤 状态表示 &#xff1a;dp数组中每一个下标对应值的含义是什么->dp[i]表示什么状态转移方程&#xff1a; dp[i] 等于什么1 和 2 是…

NRF52832修改OTA升级时的bootloader蓝牙MAC

NRF52832在OTA升级时&#xff0c;修改了APP的蓝牙MAC会导致无法升级&#xff0c;原因是OTA程序的蓝牙MAC没有被修改所以手机扫描蓝牙时无法连接 解决办法 在bootloader的程序里面加入修改蓝牙mac地址的代码实现原理&#xff1a; 在bootloader蓝牙广播开启之前修改蓝牙mac 通…

轻松编辑照片,无需下载!2024年最受推荐的在线PS替代工具

设计领域&#xff0c;Adobe Photoshop无疑是最受欢迎的软件之一。然而&#xff0c;PS对初学者来说可能很复杂&#xff0c;需要安装在计算机上&#xff0c;更不用说相对昂贵的价格了。这些因素使得PS在线网页替代设计工具越来越受欢迎。今天&#xff0c;我们将为您介绍一些优秀的…

[Leetcode笔记] 滑动窗口相关

前言 今天做leetcode的时候遇到一道滑动窗口相关的题目&#xff0c;题目具体内容如下&#xff1a; 思路 这道题很显然需要用到滑动窗口&#xff0c;肯定不是让你傻乎乎一遍一遍去遍历数组的内容然后遍历尝试 流程&#xff1a; 先算数组的总大小。使用while计算滑动窗口数…

第十二届蓝桥杯JavaA组省赛真题 - 相乘

解题思路&#xff1a; 暴力 public class Main {public static void main(String[] args) {for (long i 1; i < 1000000007; i) {if (i * 2021 % 1000000007 999999999) System.out.print(i);else System.out.print(0);}} }

LeetCode-统计完全连通分量的数量

题目要求&#xff1a; 给你一个整数 n 。现有一个包含 n 个顶点的 无向 图&#xff0c;顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。 返回图中 完全连通分量 的数量。 如果在子图中任意两个顶点…

揭秘速成软件书:彩虹之下的真相

在这个信息爆炸的时代&#xff0c;我们常常被诱惑性的标题所吸引&#xff1a;“三天掌握Python编程”&#xff0c;“一周精通Photoshop”&#xff0c;书架上堆满了各种各样的速成指南&#xff0c;这些声称能迅速提升技能的书籍&#xff0c;真的能做到它们所承诺的吗&#xff1f…

前任在代码里下毒,支付下单居然没加幂等?

首先蜗牛和大家从以下几个方面好好剖析一下接口幂等吧。 什么是接口幂等 比较专业的术语&#xff1a;其任意多次执行所产生的影响均与第一次执行的影响相同。 也就是多次调用的情况下&#xff0c;接口最终得到的结果是一致的。 那么为什么需要幂等呢&#xff1f; 那么哪些接…

数据结构03:栈、队列和数组 队习题01[C++]

考研笔记整理~&#x1f95d;&#x1f95d; 之前的博文链接在此&#xff1a;数据结构03&#xff1a;栈、队列和数组_-CSDN博客~&#x1f95d;&#x1f95d; 本篇作为链表的代码补充&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;王道书的课后习题…

实战-后台管理系统SQL注入漏洞

对于edu来说&#xff0c;是新人挖洞较好的平台&#xff0c;本次记录一次走运的捡漏0x01 前景 在进行fofa盲打站点的时候&#xff0c;来到了一个后台管理处看到集市二字&#xff0c;应该是edu站点 确认目标身份&#xff08;使用的quake进行然后去ipc备案查询&#xff09; 网…

Qt实现Kermit协议(一)

1 概述 Kermit文件运输协议提供了一条从大型计算机下载文件到微机的途径。它已被用于进行公用数据传输。 其特性如下: Kermit文件运输协议是一个半双工的通信协议。它支持7位ASCII字符。数据以可多达96字节长度的可变长度的分组形式传输。对每个被传送分组需要一个确认。Kerm…

关于视场角,你需要知道这些!

视场角在光学工程中又称视场&#xff0c;视场角的大小决定了光学仪器的视野范围。视场角又可用FOV&#xff08;Field of view&#xff09;表示&#xff0c;其与焦距的关系如下&#xff1a;像高 EFL*tan (半FOV)&#xff1b;EFL为焦距&#xff1b;FOV为视场角。即以入瞳位置为顶…

一个包一条命令,我实现了对整个前端项目代码的校验

在现代前端开发中&#xff0c;代码校验与风格统一不仅是良好编程习惯的体现&#xff0c;更是提升项目质量、保障代码可维护性与减少潜在bug的关键环节。然而&#xff0c;面对诸如ESLint、Commitlint、Stylelint等多样化的校验工具&#xff0c;以及针对React、Vue等不同前端框架…

笔记本电脑上部署LLaMA-2中文模型

尝试在macbook上部署LLaMA-2的中文模型的详细过程。 &#xff08;1&#xff09;环境准备 MacBook Pro(M2 Max/32G); VMware Fusion Player 版本 13.5.1 (23298085); Ubuntu 22.04.2 LTS; 给linux虚拟机分配8*core CPU 16G RAM。 我这里用的是16bit的量化模型&#xff0c;…

java线程(一)--进程,多线程,synchronized和lock锁,JUC,JUnit

Java线程入门 单核CPU和多核CPU的理解 单核CPU&#xff0c;其实是一种假的多线程&#xff0c;因为在一个时间单元内&#xff0c;也只能执行一个线程的任务。例如&#xff1a;虽然有多车道&#xff0c;但是收费站只有一个工作人员在收费&#xff0c;只有收了费才能通过&#xf…

LeetCode226:反转二叉树

题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 解题思想 使用前序遍历和后序遍历比较方便 代码 class Solution { public:TreeNode* invertTree(TreeNode* root) {if (root nullptr) return root;swap(root->left, root…

什么是ISP住宅IP?相比于普通IP它的优势是什么?

什么是ISP住宅IP&#xff1f; ISP住宅IP是指由互联网服务提供商&#xff08;ISP&#xff09;分配给住宅用户的IP地址。它是用户在家庭网络环境中连接互联网的标识符&#xff0c;通常用于上网浏览、数据传输等活动。ISP住宅IP可以是动态分配的&#xff0c;即每次连接时都可能会…

BOM系统:贯穿制造全程的管理利器

在制造行业中&#xff0c;BOM系统的应用已经成为提高生产效率、降低成本和确保产品质量的关键因素。BOM系统作为产品结构和物料清单的管理工具&#xff0c;为制造企业提供了全面的控制和协同能力。 1.产品设计与开发&#xff1a;在产品设计阶段&#xff0c;BOM系统为工程师提供…

基于自动编码器的预训练模型方法模型预训练方法RetroMAE和RetroMAE-2

文章目录 RetroMAERetroMAE详情编码解码增强解码 RetroMAE-2RetroMAE-2详情编码[CLS]解码OT解码和训练目标向量表征 总结参考资料 RetroMAE RetroMAE 出自论文《RetroMAE: Pre-Training Retrieval-oriented Language Models Via Masked Auto-Encoder》&#xff0c;是一种针对于…

ES-7.12-官方文档阅读-ILM-Automate rollover

教程&#xff1a;使用ILM自动化滚动创建index 当你持续将带有时间戳的文档index到Elasticsearch当中时&#xff0c;通常会使用数据流&#xff08;data streams&#xff09;以便可以定义滚到到新索引。这是你能够实施一个hot-warm-cold架构来满足你的性能要强&#xff0c;控制随…