PullToDismissPager点击按钮,从底部弹出对话框,对话框可以是多个滑动界面,里面可以放各式各样的布局,随性而发
这是个eclipse的demo,
PullToDismissPager
package com.mrbug.pulltodismisspager; import android.annotation.SuppressLint; /** * Created by krntija on 9/2/14. */ public class PullToDismissPager extends ViewGroup { private static final String TAG = PullToDismissPager.class.getSimpleName(); /** * Default initial state for the component */ private static SlideState DEFAULT_SLIDE_STATE = SlideState.COLLAPSED; /** * If no fade color is given by default it will fade to 80% gray. */ private static final int DEFAULT_FADE_COLOR = 0x99000000; /** * Default Minimum velocity that will be detected as a fling */ private static final int DEFAULT_MIN_FLING_VELOCITY = 400; // dips per second /** * Default attributes for layout */ private static final int[] DEFAULT_ATTRS = new int[] { android.R.attr.gravity }; /** * Minimum velocity that will be detected as a fling */ private int mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY; /** * The fade color used for the panel covered by the slider. 0 = no fading. */ private int mCoveredFadeColor = DEFAULT_FADE_COLOR; /** * The paint used to dim the main layout when sliding */ private final Paint mCoveredFadePaint = new Paint(); /** * True if the collapsed panel should be dragged up. */ private boolean mIsSlidingUp; /** * If provided, the panel can be dragged by only this view. Otherwise, the entire panel can be * used for dragging. */ private View mDragView; /** * The child view that can slide, if any. */ private View mSlideableView; /** * The main view */ private View mMainView; /** * Current state of the slideable view. */ private enum SlideState { EXPANDED, COLLAPSED, HIDDEN, DRAGGING } private SlideState mSlideState = SlideState.COLLAPSED; /** * How far the panel is offset from its expanded position. * range [0, 1] where 0 = collapsed, 1 = expanded. */ private float mSlideOffset; /** * How far in pixels the slideable panel may move. */ private int mSlideRange; /** * A panel view is locked into internal scrolling or another condition that * is preventing a drag. */ private boolean mIsUnableToDrag; /** * Flag indicating that sliding feature is enabled\disabled */ private boolean mIsSlidingEnabled; /** * Flag indicating if a drag view can have its own touch events. If set * to true, a drag view can scroll horizontally and have its own click listener. * * Default is set to false. */ private boolean mIsUsingDragViewTouchEvents; private float mInitialMotionX; private float mInitialMotionY; private float mAnchorPoint = 1.f; private PanelSlideListener mPanelSlideListener; private final ViewDragHelper mDragHelper; private ViewPager mViewPager; /** * Stores whether or not the pane was expanded the last time it was slideable. * If expand/collapse operations are invoked this state is modified. Used by * instance state save/restore. */ private boolean mFirstLayout = true; private final Rect mTmpRect = new Rect(); /** * Listener for monitoring events about sliding panes. */ public interface PanelSlideListener { /** * Called when a sliding pane's position changes. * @param panel The child view that was moved * @param slideOffset The new offset of this sliding pane within its range, from 0-1 */ public void onPanelSlide(View panel, float slideOffset); /** * Called when a sliding panel becomes slid completely collapsed. * @param panel The child view that was slid to an collapsed position */ public void onPanelCollapsed(View panel); /** * Called when a sliding panel becomes slid completely expanded. * @param panel The child view that was slid to a expanded position */ public void onPanelExpanded(View panel); /** * Called when a sliding panel becomes anchored. * @param panel The child view that was slid to a anchored position */ public void onPanelAnchored(View panel); /** * Called when a sliding panel becomes completely hidden. * @param panel The child view that was slid to a hidden position */ public void onPanelHidden(View panel); } /** * No-op stubs for {@link PanelSlideListener}. If you only want to implement a subset * of the listener methods you can extend this instead of implement the full interface. */ public static class SimplePanelSlideListener implements PanelSlideListener { @Override public void onPanelSlide(View panel, float slideOffset) { } @Override public void onPanelCollapsed(View panel) { } @Override public void onPanelExpanded(View panel) { } @Override public void onPanelAnchored(View panel) { } @Override public void onPanelHidden(View panel) { } } public PullToDismissPager(Context context) { this(context, null); } public PullToDismissPager(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PullToDismissPager(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); if(isInEditMode()) { mDragHelper = null; return; } if (attrs != null) { TypedArray defAttrs = context.obtainStyledAttributes(attrs, DEFAULT_ATTRS); if (defAttrs != null) { int gravity = defAttrs.getInt(0, Gravity.BOTTOM); if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) { throw new IllegalArgumentException("gravity must be set to either top or bottom"); } mIsSlidingUp = gravity == Gravity.BOTTOM; } defAttrs.recycle(); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PullToDismissPager); if (ta != null) { mMinFlingVelocity = ta.getInt(R.styleable.PullToDismissPager_flingVelocity, DEFAULT_MIN_FLING_VELOCITY); mCoveredFadeColor = ta.getColor(R.styleable.PullToDismissPager_fadeColor, DEFAULT_FADE_COLOR); mSlideState = SlideState.values()[ta.getInt(R.styleable.PullToDismissPager_initialState, DEFAULT_SLIDE_STATE.ordinal())]; } ta.recycle(); } final float density = context.getResources().getDisplayMetrics().density; setWillNotDraw(false); mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback()); mDragHelper.setMinVelocity(mMinFlingVelocity * density); mIsSlidingEnabled = true; mViewPager = new ViewPager(context); } /** * Set the color used to fade the pane covered by the sliding pane out when the pane * will become fully covered in the expanded state. * * @param color An ARGB-packed color value */ public void setCoveredFadeColor(int color) { mCoveredFadeColor = color; invalidate(); } /** * @return The ARGB-packed color value used to fade the fixed pane */ public int getCoveredFadeColor() { return mCoveredFadeColor; } /** * Set sliding enabled flag * @param enabled flag value */ public void setSlidingEnabled(boolean enabled) { mIsSlidingEnabled = enabled; } public boolean isSlidingEnabled() { return mIsSlidingEnabled && mSlideableView != null; } /** * Sets the panel slide listener * @param listener */ public void setPanelSlideListener(PanelSlideListener listener) { mPanelSlideListener = listener; } public ViewPager getViewPager(){ return mViewPager; } public void setPagerAdapter(PagerAdapter pagerAdapter){ if(this.mViewPager != null) this.mViewPager.setAdapter(pagerAdapter); } /** * Set the draggable view portion. Use to null, to allow the whole panel to be draggable * * @param dragView A view that will be used to drag the panel. */ public void setDragView(View dragView) { if (mDragView != null) { mDragView.setOnClickListener(null); } mDragView = dragView; if (mDragView != null) { mDragView.setClickable(true); mDragView.setFocusable(false); mDragView.setFocusableInTouchMode(false); mDragView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!isEnabled()) return; if (!isPanelExpanded()) { expandPanel(mAnchorPoint); } else { collapsePanel(); } } });; } } void dispatchOnPanelSlide(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelSlide(panel, mSlideOffset); } } void dispatchOnPanelExpanded(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelExpanded(panel); } sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } void dispatchOnPanelCollapsed(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelCollapsed(panel); } sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } void dispatchOnPanelAnchored(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelAnchored(panel); } sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } void dispatchOnPanelHidden(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelHidden(panel); } sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } void updateObscuredViewVisibility() { if (getChildCount() == 0) { return; } final int leftBound = getPaddingLeft(); final int rightBound = getWidth() - getPaddingRight(); final int topBound = getPaddingTop(); final int bottomBound = getHeight() - getPaddingBottom(); final int left; final int right; final int top; final int bottom; if (mSlideableView != null && hasOpaqueBackground(mSlideableView)) { left = mSlideableView.getLeft(); right = mSlideableView.getRight(); top = mSlideableView.getTop(); bottom = mSlideableView.getBottom(); } else { left = right = top = bottom = 0; } View child = getChildAt(0); final int clampedChildLeft = Math.max(leftBound, child.getLeft()); final int clampedChildTop = Math.max(topBound, child.getTop()); final int clampedChildRight = Math.min(rightBound, child.getRight()); final int clampedChildBottom = Math.min(bottomBound, child.getBottom()); final int vis; if (clampedChildLeft >= left && clampedChildTop >= top && clampedChildRight <= right && clampedChildBottom <= bottom) { vis = INVISIBLE; } else { vis = VISIBLE; } child.setVisibility(vis); } void setAllChildrenVisible() { for (int i = 0, childCount = getChildCount(); i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() == INVISIBLE) { child.setVisibility(VISIBLE); } } } private static boolean hasOpaqueBackground(View v) { final Drawable bg = v.getBackground(); return bg != null && bg.getOpacity() == PixelFormat.OPAQUE; } @Override protected void onFinishInflate() { super.onFinishInflate(); this.addView(mViewPager); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mFirstLayout = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mFirstLayout = true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int widthSize = MeasureSpec.getSize(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); final int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("Width must have an exact value or MATCH_PARENT"); } else if (heightMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("Height must have an exact value or MATCH_PARENT"); } final int childCount = getChildCount(); if (childCount != 2) { throw new IllegalStateException("You can add exactly 1 child!"); } mMainView = getChildAt(0); mSlideableView = getChildAt(1); if (mDragView == null) { setDragView(mSlideableView); } // If the sliding panel is not visible, then put the whole view in the hidden state if (mSlideableView.getVisibility() == GONE) { mSlideState = SlideState.HIDDEN; } int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom(); // First pass. Measure based on child LayoutParams width/height. for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); // We always measure the sliding panel in order to know it's height (needed for show panel) if (child.getVisibility() == GONE && i == 0) { continue; } int height = layoutHeight; int childWidthSpec; if (lp.width == LayoutParams.WRAP_CONTENT) { childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST); } else if (lp.width == LayoutParams.MATCH_PARENT) { childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); } else { childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); } int childHeightSpec; if (lp.height == LayoutParams.WRAP_CONTENT) { childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); } else if (lp.height == LayoutParams.MATCH_PARENT) { childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } child.measure(childWidthSpec, childHeightSpec); if (child == mSlideableView) { mSlideRange = mSlideableView.getMeasuredHeight(); } } setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int paddingLeft = getPaddingLeft(); final int paddingTop = getPaddingTop(); final int childCount = getChildCount(); if (mFirstLayout) { switch (mSlideState) { case EXPANDED: mSlideOffset = 1.0f; break; case HIDDEN: int newTop = computePanelTopPosition(0.0f); mSlideOffset = computeSlideOffset(newTop); break; default: mSlideOffset = 0.f; break; } } for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); // Always layout the sliding view on the first layout if (child.getVisibility() == GONE && (i == 0 || mFirstLayout)) { continue; } final int childHeight = child.getMeasuredHeight(); int childTop = paddingTop; if (child == mSlideableView) { childTop = computePanelTopPosition(mSlideOffset); } if (!mIsSlidingUp) { if (child == mMainView) { childTop = computePanelTopPosition(mSlideOffset) + mSlideableView.getMeasuredHeight(); } } final int childBottom = childTop + childHeight; final int childLeft = paddingLeft; final int childRight = childLeft + child.getMeasuredWidth(); child.layout(childLeft, childTop, childRight, childBottom); } if (mFirstLayout) { updateObscuredViewVisibility(); } mFirstLayout = false; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // Recalculate sliding panes and their details if (h != oldh) { mFirstLayout = true; } } /** * Set if the drag view can have its own touch events. If set * to true, a drag view can scroll horizontally and have its own click listener. * * Default is set to false. */ public void setEnableDragViewTouchEvents(boolean enabled) { mIsUsingDragViewTouchEvents = enabled; } @Override public void setEnabled(boolean enabled) { if (!enabled) { collapsePanel(); } super.setEnabled(enabled); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); if (!isEnabled() || !mIsSlidingEnabled || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) { mDragHelper.cancel(); return super.onInterceptTouchEvent(ev); } if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mDragHelper.cancel(); return false; } final float x = ev.getX(); final float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: { mIsUnableToDrag = false; mInitialMotionX = x; mInitialMotionY = y; break; } case MotionEvent.ACTION_MOVE: { final float adx = Math.abs(x - mInitialMotionX); final float ady = Math.abs(y - mInitialMotionY); final int dragSlop = mDragHelper.getTouchSlop(); // Handle any horizontal scrolling on the drag view. if (mIsUsingDragViewTouchEvents && adx > dragSlop && ady < dragSlop) { return super.onInterceptTouchEvent(ev); } if ((ady > dragSlop && adx > ady) || !isDragViewUnder((int)mInitialMotionX, (int)mInitialMotionY)) { mDragHelper.cancel(); mIsUnableToDrag = true; return false; } break; } } return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { if (!isSlidingEnabled()) { return super.onTouchEvent(ev); } mDragHelper.processTouchEvent(ev); return true; } private boolean isDragViewUnder(int x, int y) { if (mDragView == null) return false; int[] viewLocation = new int[2]; mDragView.getLocationOnScreen(viewLocation); int[] parentLocation = new int[2]; this.getLocationOnScreen(parentLocation); int screenX = parentLocation[0] + x; int screenY = parentLocation[1] + y; return screenX >= viewLocation[0] && screenX < viewLocation[0] + mDragView.getWidth() && screenY >= viewLocation[1] && screenY < viewLocation[1] + mDragView.getHeight(); } private boolean expandPanel(View pane, int initialVelocity, float mSlideOffset) { return mFirstLayout || smoothSlideTo(mSlideOffset, initialVelocity); } private boolean collapsePanel(View pane, int initialVelocity) { return mFirstLayout || smoothSlideTo(0.0f, initialVelocity); } /* * Computes the top position of the panel based on the slide offset. */ private int computePanelTopPosition(float slideOffset) { int slidingViewHeight = mSlideableView != null ? mSlideableView.getMeasuredHeight() : 0; int slidePixelOffset = (int) (slideOffset * mSlideRange); // Compute the top of the panel if its collapsed return mIsSlidingUp ? getMeasuredHeight() - getPaddingBottom() - slidePixelOffset : getPaddingTop() - slidingViewHeight + slidePixelOffset; } /* * Computes the slide offset based on the top position of the panel */ private float computeSlideOffset(int topPosition) { // Compute the panel top position if the panel is collapsed (offset 0) final int topBoundCollapsed = computePanelTopPosition(0); // Determine the new slide offset based on the collapsed top position and the new required // top position return (mIsSlidingUp ? (float) (topBoundCollapsed - topPosition) / mSlideRange : (float) (topPosition - topBoundCollapsed) / mSlideRange); } /** * Collapse the sliding pane if it is currently slideable. If first layout * has already completed this will animate. * * @return true if the pane was slideable and is now collapsed/in the process of collapsing */ public boolean collapsePanel() { if (mFirstLayout) { mSlideState = SlideState.COLLAPSED; return true; } else { if (mSlideState == SlideState.HIDDEN || mSlideState == SlideState.COLLAPSED) return false; return collapsePanel(mSlideableView, 0); } } /** * Expand the sliding pane if it is currently slideable. * * @return true if the pane was slideable and is now expanded/in the process of expading */ public boolean expandPanel() { if (mFirstLayout) { mSlideState = SlideState.EXPANDED; return true; } else { return expandPanel(1.0f); } } /** * Partially expand the sliding panel up to a specific offset * * @param mSlideOffset Value between 0 and 1, where 0 is completely expanded. * @return true if the pane was slideable and is now expanded/in the process of expanding */ public boolean expandPanel(float mSlideOffset) { if (mSlideableView == null || mSlideState == SlideState.EXPANDED) return false; mSlideableView.setVisibility(View.VISIBLE); return expandPanel(mSlideableView, 0, mSlideOffset); } /** * Check if the sliding panel in this layout is fully expanded. * * @return true if sliding panel is completely expanded */ public boolean isPanelExpanded() { return mSlideState == SlideState.EXPANDED; } /** * Check if the sliding panel in this layout is currently visible. * * @return true if the sliding panel is visible. */ public boolean isPanelHidden() { return mSlideState == SlideState.HIDDEN; } /** * Shows the panel from the hidden state */ public void showPanel() { if (mFirstLayout) { mSlideState = SlideState.COLLAPSED; } else { if (mSlideableView == null || mSlideState != SlideState.HIDDEN) return; mSlideableView.setVisibility(View.VISIBLE); requestLayout(); smoothSlideTo(0, 0); } } /** * Hides the sliding panel entirely. */ public void hidePanel() { if (mFirstLayout) { mSlideState = SlideState.HIDDEN; } else { if (mSlideState == SlideState.DRAGGING || mSlideState == SlideState.HIDDEN) return; int newTop = computePanelTopPosition(0.0f); smoothSlideTo(computeSlideOffset(newTop), 0); } } @SuppressLint("NewApi") private void onPanelDragged(int newTop) { mSlideState = SlideState.DRAGGING; // Recompute the slide offset based on the new top position mSlideOffset = computeSlideOffset(newTop); // Dispatch the slide event dispatchOnPanelSlide(mSlideableView); // If the slide offset is negative, and overlay is not on, we need to increase the // height of the main content if (mSlideOffset <= 0) { // expand the main view LayoutParams lp = (LayoutParams)mMainView.getLayoutParams(); lp.height = mIsSlidingUp ? (newTop - getPaddingBottom()) : (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() - newTop); mMainView.requestLayout(); } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result; final int save = canvas.save(Canvas.CLIP_SAVE_FLAG); if (isSlidingEnabled() && mSlideableView != child) { canvas.getClipBounds(mTmpRect); canvas.clipRect(mTmpRect); } if (mCoveredFadeColor != 0 && mSlideOffset > 0) { final int baseAlpha = (mCoveredFadeColor & 0xff000000) >>> 24; final int imag = (int) (baseAlpha * mSlideOffset); final int color = imag << 24 | (mCoveredFadeColor & 0xffffff); mCoveredFadePaint.setColor(color); canvas.drawRect(mTmpRect, mCoveredFadePaint); } result = super.drawChild(canvas, child, drawingTime); canvas.restoreToCount(save); return result; } /** * Smoothly animate mDraggingPane to the target X position within its range. * * @param slideOffset position to animate to * @param velocity initial velocity in case of fling, or 0. */ boolean smoothSlideTo(float slideOffset, int velocity) { if (!isSlidingEnabled()) { // Nothing to do. return false; } int panelTop = computePanelTopPosition(slideOffset); if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop)) { setAllChildrenVisible(); ViewCompat.postInvalidateOnAnimation(this); return true; } return false; } @Override public void computeScroll() { if (mDragHelper != null && mDragHelper.continueSettling(true)) { if (!isSlidingEnabled()) { mDragHelper.abort(); return; } ViewCompat.postInvalidateOnAnimation(this); } } @Override public void draw(Canvas c) { super.draw(c); if (!isSlidingEnabled()) { // No need to draw a shadow if we don't have one. return; } } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(); } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : new LayoutParams(p); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams && super.checkLayoutParams(p); } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.mSlideState = mSlideState; return ss; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mSlideState = ss.mSlideState; } private class DragHelperCallback extends ViewDragHelper.Callback { @Override public boolean tryCaptureView(View child, int pointerId) { if (mIsUnableToDrag) { return false; } return child == mSlideableView; } @Override public void onViewDragStateChanged(int state) { if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) { mSlideOffset = computeSlideOffset(mSlideableView.getTop()); if (mSlideOffset == 1) { if (mSlideState != SlideState.EXPANDED) { updateObscuredViewVisibility(); mSlideState = SlideState.EXPANDED; dispatchOnPanelExpanded(mSlideableView); } } else if (mSlideOffset == 0) { if (mSlideState != SlideState.COLLAPSED) { mSlideState = SlideState.COLLAPSED; dispatchOnPanelCollapsed(mSlideableView); } } else if (mSlideOffset < 0) { mSlideState = SlideState.HIDDEN; mSlideableView.setVisibility(View.GONE); dispatchOnPanelHidden(mSlideableView); } } } @Override public void onViewCaptured(View capturedChild, int activePointerId) { setAllChildrenVisible(); } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { onPanelDragged(top); invalidate(); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { int target = 0; // direction is always positive if we are sliding in the expanded direction float direction = mIsSlidingUp ? -yvel : yvel; if (direction > 0) { // swipe up -> expand target = computePanelTopPosition(1.0f); } else if (direction < 0) { // swipe down -> collapse target = computePanelTopPosition(0.0f); } else if (mAnchorPoint != 1 && mSlideOffset >= (1.f + mAnchorPoint) / 2) { // zero velocity, and far enough from anchor point => expand to the top target = computePanelTopPosition(1.0f); } else if (mAnchorPoint == 1 && mSlideOffset >= 0.5f) { // zero velocity, and far enough from anchor point => expand to the top target = computePanelTopPosition(1.0f); } else if (mAnchorPoint != 1 && mSlideOffset >= mAnchorPoint) { target = computePanelTopPosition(mAnchorPoint); } else if (mAnchorPoint != 1 && mSlideOffset >= mAnchorPoint / 2) { target = computePanelTopPosition(mAnchorPoint); } else { // settle at the bottom target = computePanelTopPosition(0.0f); } mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target); invalidate(); } @Override public int getViewVerticalDragRange(View child) { return mSlideRange; } @Override public int clampViewPositionVertical(View child, int top, int dy) { final int collapsedTop = computePanelTopPosition(0.f); final int expandedTop = computePanelTopPosition(1.0f); if (mIsSlidingUp) { return Math.min(Math.max(top, expandedTop), collapsedTop); } else { return Math.min(Math.max(top, collapsedTop), expandedTop); } } } public static class LayoutParams extends ViewGroup.MarginLayoutParams { private static final int[] ATTRS = new int[] { android.R.attr.layout_weight }; public LayoutParams() { super(MATCH_PARENT, MATCH_PARENT); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(android.view.ViewGroup.LayoutParams source) { super(source); } public LayoutParams(MarginLayoutParams source) { super(source); } public LayoutParams(LayoutParams source) { super(source); } public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS); a.recycle(); } } static class SavedState extends BaseSavedState { SlideState mSlideState; SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); try { mSlideState = Enum.valueOf(SlideState.class, in.readString()); } catch (IllegalArgumentException e) { mSlideState = SlideState.COLLAPSED; } } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeString(mSlideState.toString()); } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }
MyActivity.java
package com.mrbug.pulltodismisspager.example; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.mrbug.pulltodismisspager.PullToDismissPager; public class MyActivity extends Activity { private PullToDismissPager pull_to_dismiss_pager; private PagerAdapter pagerAdapter; private Button button; String[] imgs={"http://c.hiphotos.baidu.com/image/pic/item/0dd7912397dda1449fad6f63b6b7d0a20df486be.jpg", "http://h.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a9bd0374211a178a82b80114c6.jpg", "http://d.hiphotos.baidu.com/image/pic/item/71cf3bc79f3df8dcd227017cc911728b461028c0.jpg", "http://d.hiphotos.baidu.com/image/pic/item/2fdda3cc7cd98d10ba9982dc253fb80e7aec908a.jpg", "http://g.hiphotos.baidu.com/image/pic/item/0b55b319ebc4b7457d3839fbcbfc1e178b8215aa.jpg", "http://b.hiphotos.baidu.com/image/pic/item/d009b3de9c82d15825ffd75c840a19d8bd3e42da.jpg"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); button =(Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub pull_to_dismiss_pager.expandPanel(); } }); pull_to_dismiss_pager = (PullToDismissPager) findViewById(R.id.pull_to_dismiss_pager); pagerAdapter = new SlidingPagerAdapter(this); pull_to_dismiss_pager.setPagerAdapter(pagerAdapter); } @Override public void onBackPressed() { if(pull_to_dismiss_pager.isPanelExpanded()) pull_to_dismiss_pager.collapsePanel(); else super.onBackPressed(); } private class SlidingPagerAdapter extends PagerAdapter{ private LayoutInflater mInflater; private Context mcontext; public SlidingPagerAdapter(Context context){ mInflater = LayoutInflater.from(context); mcontext=context; } @Override public int getCount() { return imgs.length; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = mInflater.inflate(R.layout.pager_item, null, false); TextView item =(TextView) view.findViewById(R.id.item1); ImageView img =(ImageView) view.findViewById(R.id.img); Glide.with(mcontext).load(imgs[position]).into(img); item.setText(position+""); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((FrameLayout)object); } } }
demo如下,
相关推荐
ChatUI-master是一个专门为Android平台设计的用户界面(UI)项目,其主要目标是仿照微信的对话框界面,提供一个类似的功能和视觉体验。在移动应用开发中,UI设计至关重要,因为它直接影响到用户的使用体验和应用程序...
windows-folder-remark-master.zip windows-folder-remark-master.zip windows-folder-remark-master.zip windows-folder-remark-master.zip windows-folder-remark-master.zip windows-folder-remark-master.zip ...
electron-quick-start-master 快速入门教程electron-quick-start-master 快速入门教程electron-quick-start-master 快速入门教程electron-quick-start-master 快速入门教程electron-quick-start-master 快速入门教程...
最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master最新 docx4j-master...
实现仿iOS底部弹出对话框,我们有以下几种方法: 1. 自定义布局:通过编程实现自定义的对话框布局,包括背景色、圆角、边距等属性,以及动画效果。例如,我们可以使用Android的`PopupWindow`类来创建一个自定义视图...
带有各种动画效果的弹出对话框控件。你也可以自定义样式及弹出动画。效果非常棒,且使用简单。项目地址:https://github.com/H07000223/FlycoDialog_Master 效果图: 依赖的库文件: FlycoAnimation_Lib ...
字符云 hamrry-DongTaiCiYun-master字符云 hamrry-DongTaiCiYun-master字符云 hamrry-DongTaiCiYun-master字符云 hamrry-DongTaiCiYun-master字符云 hamrry-DongTaiCiYun-master字符云 hamrry-DongTaiCiYun-master...
字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud-master字符云 WordCloud...
"uni-app 自定义底部导航栏uni-app-bottom-navigation-master.zip" 是一个针对uni-app框架的项目,其核心功能是实现自定义底部导航栏。uni-app是一个多端开发框架,允许开发者使用一套代码生成包括iOS、Android、H5...
MVSNet_pytorch版 源码 MVSNet_pytorch-master MVSNet_pytorch版 源码 MVSNet_pytorch-master MVSNet_pytorch版 源码 MVSNet_pytorch-master MVSNet_pytorch版 源码 MVSNet_pytorch-masterMVSNet_pytorch版 源码 ...
《mstar-bin-tool-master正式版:一键解包与打包利器》 在IT行业中,高效的工作流程是提升开发效率的关键。mstar-bin-tool-master正式版的出现,为处理bin文件的解包与打包工作提供了一站式的解决方案。这个工具...
在Android应用开发中,"列表长按,弹出对话框按钮"是一个常见的交互设计,它提高了用户对数据操作的便捷性。在这个场景中,当用户在列表视图中长按某一项时,会触发一个对话框,对话框内通常包含一系列可供选择的...
4. **插件市场**:uni-app有丰富的插件市场,提供了各种组件和插件,uni-preset-vue-master可能已经预装了一些常用组件,如导航栏、底部tabbar、弹窗等,方便快速构建界面。 5. **预处理语言**:uni-preset-vue-...
zxing-cpp-master\cli zxing-cpp-master\cmake zxing-cpp-master\core zxing-cpp-master\opencv zxing-cpp-master\opencv-cli zxing-cpp-master\.gitignore zxing-cpp-master\README.md zxing-cpp-master\...
开源的网站商城系统hashmart-master.zip开源的网站商城系统hashmart-master.zip开源的网站商城系统hashmart-master.zip开源的网站商城系统hashmart-master.zip开源的网站商城系统hashmart-master.zip开源的网站商城...
"cat-blender-plugin-master" 是一个专门为Blender设计的插件项目,主要目的是为了帮助用户在Blender中处理和创建与猫相关的内容。Blender是一款强大的开源3D创作软件,广泛应用于动画、游戏开发、视觉效果等领域。...
"sweetalert-master"是一个专为前端开发者设计的插件,它提供了iOS风格的弹出层,旨在让开发者能够轻松地在网页中实现美观、易用的提示对话框,从而提升用户的使用体验。 首先,我们来深入理解一下"弹出层"这一概念...
《guns-vip-master框架详解与应用指南》 guns-vip-master 是一个专为开发者设计的高效、便捷的Java开发框架,特别适用于快速构建企业级应用系统。其版本V3.4是该框架的一个重要里程碑,增加了代码生成工具,极大地...
Bootstrap3-Dialog是一款基于Bootstrap框架的对话框插件,它扩展了Bootstrap的模态功能,提供了更为丰富的定制选项和交互体验。在Web开发中,对话框通常用于展示警告、确认信息,或者进行用户输入等交互操作。...