Android仿高德首页三段式滑动

news/2024/7/26 10:57:29/文章来源:https://blog.csdn.net/u014741977/article/details/137232087

最近发现很多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.luyixian.cn/news_show_1034437.aspx

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

相关文章

010_documentation_in_Matlab中的帮助与文档

Matlab中的帮助与文档 1. 前言 一眨眼已经写了十篇文章。 000在Matlab中使用Python包CoolProp001Matlab运行时间测试与时间复杂度分析002避免使用for循环003Matlab中的向量约定004Matlab中的矩阵约定005Matlab中的数组索引006Matlab中的逻辑数组索引007Matlab学习的启动与加…

研发图纸管理软件,研发图纸管理软件解决方案

研发图纸管理软件行业的排名因市场变化和技术发展而不断变化&#xff0c;因此很难给出一个确切的排名。不过&#xff0c;以下是一些在研发图纸管理软件领域具有较高知名度和影响力的品牌&#xff0c;它们提供了丰富的功能和解决方案&#xff0c;帮助企业更好地管理和利用研发图…

uniapp创建opendb-city-china Schema文件后,如何导入城市的数据?

1.点击opendb-city-china后面的详情&#xff0c;进入到gitee代码仓库 2.下载如下图所示的data.json文件 3.将本地创建的opendb-city-china.schema.json上传到云端 4.点击导入json 如果直接将data.json导入会报错&#xff0c;如下图所示: 5.将data.json本来的数组对象&#…

游戏引擎架构01__引擎架构图

根据游戏引擎架构预设的引擎架构来构建运行时引擎架构 ​

idea端口占用

报错&#xff1a;Verify the connector‘s configuration, identify and stop any process that‘s listening on port XXXX 翻译&#xff1a; 原因&#xff1a; 解决&#xff1a; 一、重启大法 二、手动关闭 启动spring项目是控制台报错&#xff0c;详细信息如下&#xff…

【机器学习300问】61、逻辑回归与线性回归的异同?

本文讲述两个经典机器学习逻辑回归&#xff08;Logistic Regression&#xff09;和线性回归&#xff08;Linear Regression&#xff09;算法的异同&#xff0c;有助于我们在面对实际问题时更好的进行模型选择。也能帮助我们加深对两者的理解&#xff0c;掌握这两类基础模型有助…

kubernetes-dashboard 安装配置

k8s 1.23以上的版本 https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml 执行命令&#xff1a; kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml 安装完成后&#x…

【剑指offer】顺时针打印矩阵

题目链接 acwing leetcode 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 数据范围矩阵中元素数量 [0,400]。 输入&#xff1a; [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出&#xff1a;[1,2,3,4,8,12,11,10,9,5,6,7] 解题 …

前端小白如何理解mvc mvp mvvm

架构、框架、设计模式是都是啥&#xff1f; 架构&#xff1a;抽象出来不同组织或者对象亦或是简单组件&#xff0c;根据需求和各个单元的功能&#xff0c;进行组合排列。 从而完成系统的运行或者是实现目标。 框架&#xff1a;使用什么样的规则&#xff0c;什么样的开发语言&…

微信小程序-文字转语音(播放及暂停)

1、使用微信小程序的同声传译功能 小程序平台-设置-第三方设置-插件管理-新增同声传译插件 小程序app.json文件配置 "plugins": {"WechatSI": {"version": "0.3.5","provider": "wx069ba97219f66d99"}},小程序中…

旅游管理系统|基于Springboot的旅游管理系统设计与实现(源码+数据库+文档)

旅游管理系统目录 目录 基于Springboot的旅游管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户管理 2、景点分类管理 3、景点信息管理 4、酒店信息管理 5、景点信息 6、游记分享管理 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xf…

达梦DMHS-Manager工具安装部署

目录 1、前言 1.1、平台架构 1.2、平台原理 2、环境准备 2.1、硬件环境 2.2、软件环境 2.3、安装DMHS 2.3.1、源端DMHS前期准备 2.3.2、源端DMHS安装 2.3.3、目的端DMHS安装 3、DMHS-Manager客户端部署 3.1、启动dmhs web服务 3.2、登录web管理平台 4、添加DMHS实…

javaweb学习(day10-服务器渲染技术)

一、基本介绍 1.前言 目前主流的技术是 前后端分离 (比如: Spring Boot Vue/React)JSP 技术使用在逐渐减少&#xff0c;但使用少和没有使用是两个意思&#xff0c;一些老项目和中小公司还在使用 JSP&#xff0c;工作期间&#xff0c;你很有可能遇到 JSPJSP 使用在减少(但是现…

体验OceanBase 的binlog service

OceanBase对MySQL具备很好的兼容性。目前&#xff0c;已经发布了开源版的binlog service工具&#xff0c;该工具能够将OceanBase特有的clog模式转换成binlog模式&#xff0c;以便下游工具如canal、flink cdc等使用。今天&#xff0c;我们就来简单体验一下这个binlog service的功…

day4|gin的中间件和路由分组

中间件其实是一个方法&#xff0c; 在.use就可以调用中间件函数 r : gin.Default()v1 : r.Group("v1")//v1 : r.Group("v1").Use()v1.GET("test", func(c *gin.Context) {fmt.Println("get into the test")c.JSON(200, gin.H{"…

FFmpeg获取视频详情

话不多说&#xff0c;直接上代码&#xff1a; pom依赖&#xff1a; <!--视频多媒体工具包 包含 FFmpeg、OpenCV--><dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.3</versi…

使用ffmpeg将视频解码为帧时,图像质量很差

当使用ffmpeg库自带的ffmpeg.exe对对视频进行解帧或合并时&#xff0c;结果质量很差。导致这种原因的是在使用ffmpeg.exe指令进行解帧或合并时使用的是默认的视频码率&#xff1a;200kb/s。 如解帧指令&#xff1a; ffmpeg.exe -i 600600pixels.avi -r 2 -f image2 img/%03d.…

Java项目:86 springboot电影评论网站系统设计与实现

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本电影评论网站管理员和用户。 管理员功能有个人中心&#xff0c;用户管理&#xff0c;电影类别管理&#xff0c;电影信息管理&#xff0c;留言板管理…

自贡市第一人民医院:超融合与 SKS 承载 HIS 等核心业务应用,加速国产化与云原生转型

自贡市第一人民医院始建于 1908 年&#xff0c;现已发展成为集医疗、科研、教学、预防、公共卫生应急处置为一体的三级甲等综合公立医院。医院建有“全国综合医院中医药工作示范单位”等 8 个国家级基地&#xff0c;建成高级卒中中心、胸痛中心等 6 个国家级中心。医院日门诊量…

wife_wife【web 攻防世界】

大佬的wp:WEB&#xff1a;Wife_wife-CSDN博客 知识点&#xff1a; prototype是new class 的一个属性&#xff0c;即__proto__指向new class 的prototype属性__proto__如果作为json代码解析的话会被当成键名处理&#xff0c;但是如果是在类中的话则会被当成子类的原型 如let o…