Fields Summary |
---|
private static final String | TAG |
private static final int | DEFAULT_OVERHANG_SIZEDefault size of the overhang for a pane in the open state.
At least this much of a sliding pane will remain visible.
This indicates that there is more content available and provides
a "physical" edge to grab to pull it closed. |
private static final int | DEFAULT_FADE_COLORIf no fade color is given by default it will fade to 80% gray. |
private int | mSliderFadeColorThe fade color used for the sliding panel. 0 = no fading. |
private static final int | MIN_FLING_VELOCITYMinimum velocity that will be detected as a fling |
private int | mCoveredFadeColorThe fade color used for the panel covered by the slider. 0 = no fading. |
private android.graphics.drawable.Drawable | mShadowDrawableLeftDrawable used to draw the shadow between panes by default. |
private android.graphics.drawable.Drawable | mShadowDrawableRightDrawable used to draw the shadow between panes to support RTL (right to left language). |
private final int | mOverhangSizeThe size of the overhang in pixels.
This is the minimum section of the sliding panel that will
be visible in the open state to allow for a closing drag. |
private boolean | mCanSlideTrue if a panel can slide with the current measurements |
private android.view.View | mSlideableViewThe child view that can slide, if any. |
private float | mSlideOffsetHow far the panel is offset from its closed position.
range [0, 1] where 0 = closed, 1 = open. |
private float | mParallaxOffsetHow far the non-sliding panel is parallaxed from its usual position when open.
range [0, 1] |
private int | mSlideRangeHow far in pixels the slideable panel may move. |
private boolean | mIsUnableToDragA panel view is locked into internal scrolling or another condition that
is preventing a drag. |
private int | mParallaxByDistance in pixels to parallax the fixed pane by when fully closed |
private float | mInitialMotionX |
private float | mInitialMotionY |
private PanelSlideListener | mPanelSlideListener |
private final ViewDragHelper | mDragHelper |
private boolean | mPreservedOpenStateStores whether or not the pane was open the last time it was slideable.
If open/close operations are invoked this state is modified. Used by
instance state save/restore. |
private boolean | mFirstLayout |
private final android.graphics.Rect | mTmpRect |
private final ArrayList | mPostedRunnables |
static final SlidingPanelLayoutImpl | IMPL |
Methods Summary |
---|
protected boolean | canScroll(android.view.View v, boolean checkV, int dx, int x, int y)Tests scrollability within child views of v given a delta of dx.
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int scrollX = v.getScrollX();
final int scrollY = v.getScrollY();
final int count = group.getChildCount();
// Count backwards - let topmost views consume scroll distance first.
for (int i = count - 1; i >= 0; i--) {
// TODO: Add versioned support here for transformed views.
// This will not work for transformed views in Honeycomb+
final View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
canScroll(child, true, dx, x + scrollX - child.getLeft(),
y + scrollY - child.getTop())) {
return true;
}
}
}
return checkV && ViewCompat.canScrollHorizontally(v, (isLayoutRtlSupport() ? dx : -dx));
|
public boolean | canSlide()
return mCanSlide;
|
protected boolean | checkLayoutParams(ViewGroup.LayoutParams p)
return p instanceof LayoutParams && super.checkLayoutParams(p);
|
private boolean | closePane(android.view.View pane, int initialVelocity)
if (mFirstLayout || smoothSlideTo(0.f, initialVelocity)) {
mPreservedOpenState = false;
return true;
}
return false;
|
public boolean | closePane()Close the sliding pane if it is currently slideable. If first layout
has already completed this will animate.
return closePane(mSlideableView, 0);
|
public void | computeScroll()
if (mDragHelper.continueSettling(true)) {
if (!mCanSlide) {
mDragHelper.abort();
return;
}
ViewCompat.postInvalidateOnAnimation(this);
}
|
private void | dimChildView(android.view.View v, float mag, int fadeColor)
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
if (mag > 0 && fadeColor != 0) {
final int baseAlpha = (fadeColor & 0xff000000) >>> 24;
int imag = (int) (baseAlpha * mag);
int color = imag << 24 | (fadeColor & 0xffffff);
if (lp.dimPaint == null) {
lp.dimPaint = new Paint();
}
lp.dimPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_OVER));
if (ViewCompat.getLayerType(v) != ViewCompat.LAYER_TYPE_HARDWARE) {
ViewCompat.setLayerType(v, ViewCompat.LAYER_TYPE_HARDWARE, lp.dimPaint);
}
invalidateChildRegion(v);
} else if (ViewCompat.getLayerType(v) != ViewCompat.LAYER_TYPE_NONE) {
if (lp.dimPaint != null) {
lp.dimPaint.setColorFilter(null);
}
final DisableLayerRunnable dlr = new DisableLayerRunnable(v);
mPostedRunnables.add(dlr);
ViewCompat.postOnAnimation(this, dlr);
}
|
void | dispatchOnPanelClosed(android.view.View panel)
if (mPanelSlideListener != null) {
mPanelSlideListener.onPanelClosed(panel);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
void | dispatchOnPanelOpened(android.view.View panel)
if (mPanelSlideListener != null) {
mPanelSlideListener.onPanelOpened(panel);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
void | dispatchOnPanelSlide(android.view.View panel)
if (mPanelSlideListener != null) {
mPanelSlideListener.onPanelSlide(panel, mSlideOffset);
}
|
public void | draw(android.graphics.Canvas c)
super.draw(c);
final boolean isLayoutRtl = isLayoutRtlSupport();
Drawable shadowDrawable;
if (isLayoutRtl) {
shadowDrawable = mShadowDrawableRight;
} else {
shadowDrawable = mShadowDrawableLeft;
}
final View shadowView = getChildCount() > 1 ? getChildAt(1) : null;
if (shadowView == null || shadowDrawable == null) {
// No need to draw a shadow if we don't have one.
return;
}
final int top = shadowView.getTop();
final int bottom = shadowView.getBottom();
final int shadowWidth = shadowDrawable.getIntrinsicWidth();
final int left;
final int right;
if (isLayoutRtlSupport()) {
left = shadowView.getRight();
right = left + shadowWidth;
} else {
right = shadowView.getLeft();
left = right - shadowWidth;
}
shadowDrawable.setBounds(left, top, right, bottom);
shadowDrawable.draw(c);
|
protected boolean | drawChild(android.graphics.Canvas canvas, android.view.View child, long drawingTime)
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
boolean result;
final int save = canvas.save(Canvas.CLIP_SAVE_FLAG);
if (mCanSlide && !lp.slideable && mSlideableView != null) {
// Clip against the slider; no sense drawing what will immediately be covered.
canvas.getClipBounds(mTmpRect);
if (isLayoutRtlSupport()) {
mTmpRect.left = Math.max(mTmpRect.left, mSlideableView.getRight());
} else {
mTmpRect.right = Math.min(mTmpRect.right, mSlideableView.getLeft());
}
canvas.clipRect(mTmpRect);
}
if (Build.VERSION.SDK_INT >= 11) { // HC
result = super.drawChild(canvas, child, drawingTime);
} else {
if (lp.dimWhenOffset && mSlideOffset > 0) {
if (!child.isDrawingCacheEnabled()) {
child.setDrawingCacheEnabled(true);
}
final Bitmap cache = child.getDrawingCache();
if (cache != null) {
canvas.drawBitmap(cache, child.getLeft(), child.getTop(), lp.dimPaint);
result = false;
} else {
Log.e(TAG, "drawChild: child view " + child + " returned null drawing cache");
result = super.drawChild(canvas, child, drawingTime);
}
} else {
if (child.isDrawingCacheEnabled()) {
child.setDrawingCacheEnabled(false);
}
result = super.drawChild(canvas, child, drawingTime);
}
}
canvas.restoreToCount(save);
return result;
|
protected ViewGroup.LayoutParams | generateDefaultLayoutParams()
return new LayoutParams();
|
protected ViewGroup.LayoutParams | generateLayoutParams(ViewGroup.LayoutParams p)
return p instanceof MarginLayoutParams
? new LayoutParams((MarginLayoutParams) p)
: new LayoutParams(p);
|
public ViewGroup.LayoutParams | generateLayoutParams(android.util.AttributeSet attrs)
return new LayoutParams(getContext(), attrs);
|
public int | getCoveredFadeColor()
return mCoveredFadeColor;
|
public int | getParallaxDistance()
return mParallaxBy;
|
public int | getSliderFadeColor()
return mSliderFadeColor;
|
private void | invalidateChildRegion(android.view.View v)
IMPL.invalidateChildRegion(this, v);
|
boolean | isDimmed(android.view.View child)
if (child == null) {
return false;
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
return mCanSlide && lp.dimWhenOffset && mSlideOffset > 0;
|
private boolean | isLayoutRtlSupport()
return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
|
public boolean | isOpen()Check if the layout is completely open. It can be open either because the slider
itself is open revealing the left pane, or if all content fits without sliding.
return !mCanSlide || mSlideOffset == 1;
|
public boolean | isSlideable()Check if the content in this layout cannot fully fit side by side and therefore
the content pane can be slid back and forth.
return mCanSlide;
|
protected void | onAttachedToWindow()
super.onAttachedToWindow();
mFirstLayout = true;
|
protected void | onDetachedFromWindow()
super.onDetachedFromWindow();
mFirstLayout = true;
for (int i = 0, count = mPostedRunnables.size(); i < count; i++) {
final DisableLayerRunnable dlr = mPostedRunnables.get(i);
dlr.run();
}
mPostedRunnables.clear();
|
public boolean | onInterceptTouchEvent(android.view.MotionEvent ev)
final int action = MotionEventCompat.getActionMasked(ev);
// Preserve the open state based on the last view that was touched.
if (!mCanSlide && action == MotionEvent.ACTION_DOWN && getChildCount() > 1) {
// After the first things will be slideable.
final View secondChild = getChildAt(1);
if (secondChild != null) {
mPreservedOpenState = !mDragHelper.isViewUnder(secondChild,
(int) ev.getX(), (int) ev.getY());
}
}
if (!mCanSlide || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
mDragHelper.cancel();
return super.onInterceptTouchEvent(ev);
}
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mDragHelper.cancel();
return false;
}
boolean interceptTap = false;
switch (action) {
case MotionEvent.ACTION_DOWN: {
mIsUnableToDrag = false;
final float x = ev.getX();
final float y = ev.getY();
mInitialMotionX = x;
mInitialMotionY = y;
if (mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y) &&
isDimmed(mSlideableView)) {
interceptTap = true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = ev.getX();
final float y = ev.getY();
final float adx = Math.abs(x - mInitialMotionX);
final float ady = Math.abs(y - mInitialMotionY);
final int slop = mDragHelper.getTouchSlop();
if (adx > slop && ady > adx) {
mDragHelper.cancel();
mIsUnableToDrag = true;
return false;
}
}
}
final boolean interceptForDrag = mDragHelper.shouldInterceptTouchEvent(ev);
return interceptForDrag || interceptTap;
|
protected void | onLayout(boolean changed, int l, int t, int r, int b)
final boolean isLayoutRtl = isLayoutRtlSupport();
if (isLayoutRtl) {
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
} else {
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
final int width = r - l;
final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
final int paddingEnd = isLayoutRtl ? getPaddingLeft() : getPaddingRight();
final int paddingTop = getPaddingTop();
final int childCount = getChildCount();
int xStart = paddingStart;
int nextXStart = xStart;
if (mFirstLayout) {
mSlideOffset = mCanSlide && mPreservedOpenState ? 1.f : 0.f;
}
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int childWidth = child.getMeasuredWidth();
int offset = 0;
if (lp.slideable) {
final int margin = lp.leftMargin + lp.rightMargin;
final int range = Math.min(nextXStart,
width - paddingEnd - mOverhangSize) - xStart - margin;
mSlideRange = range;
final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
lp.dimWhenOffset = xStart + lpMargin + range + childWidth / 2 >
width - paddingEnd;
final int pos = (int) (range * mSlideOffset);
xStart += pos + lpMargin;
mSlideOffset = (float) pos / mSlideRange;
} else if (mCanSlide && mParallaxBy != 0) {
offset = (int) ((1 - mSlideOffset) * mParallaxBy);
xStart = nextXStart;
} else {
xStart = nextXStart;
}
final int childRight;
final int childLeft;
if (isLayoutRtl) {
childRight = width - xStart + offset;
childLeft = childRight - childWidth;
} else {
childLeft = xStart - offset;
childRight = childLeft + childWidth;
}
final int childTop = paddingTop;
final int childBottom = childTop + child.getMeasuredHeight();
child.layout(childLeft, paddingTop, childRight, childBottom);
nextXStart += child.getWidth();
}
if (mFirstLayout) {
if (mCanSlide) {
if (mParallaxBy != 0) {
parallaxOtherViews(mSlideOffset);
}
if (((LayoutParams) mSlideableView.getLayoutParams()).dimWhenOffset) {
dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
}
} else {
// Reset the dim level of all children; it's irrelevant when nothing moves.
for (int i = 0; i < childCount; i++) {
dimChildView(getChildAt(i), 0, mSliderFadeColor);
}
}
updateObscuredViewsVisibility(mSlideableView);
}
mFirstLayout = false;
|
protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
if (isInEditMode()) {
// Don't crash the layout editor. Consume all of the space if specified
// or pick a magic number from thin air otherwise.
// TODO Better communication with tools of this bogus state.
// It will crash on a real device.
if (widthMode == MeasureSpec.AT_MOST) {
widthMode = MeasureSpec.EXACTLY;
} else if (widthMode == MeasureSpec.UNSPECIFIED) {
widthMode = MeasureSpec.EXACTLY;
widthSize = 300;
}
} else {
throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
}
} else if (heightMode == MeasureSpec.UNSPECIFIED) {
if (isInEditMode()) {
// Don't crash the layout editor. Pick a magic number from thin air instead.
// TODO Better communication with tools of this bogus state.
// It will crash on a real device.
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightMode = MeasureSpec.AT_MOST;
heightSize = 300;
}
} else {
throw new IllegalStateException("Height must not be UNSPECIFIED");
}
}
int layoutHeight = 0;
int maxLayoutHeight = -1;
switch (heightMode) {
case MeasureSpec.EXACTLY:
layoutHeight = maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
break;
case MeasureSpec.AT_MOST:
maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
break;
}
float weightSum = 0;
boolean canSlide = false;
final int widthAvailable = widthSize - getPaddingLeft() - getPaddingRight();
int widthRemaining = widthAvailable;
final int childCount = getChildCount();
if (childCount > 2) {
Log.e(TAG, "onMeasure: More than two child views are not supported.");
}
// We'll find the current one below.
mSlideableView = null;
// First pass. Measure based on child LayoutParams width/height.
// Weight will incur a second pass.
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (child.getVisibility() == GONE) {
lp.dimWhenOffset = false;
continue;
}
if (lp.weight > 0) {
weightSum += lp.weight;
// If we have no width, weight is the only contributor to the final size.
// Measure this view on the weight pass only.
if (lp.width == 0) continue;
}
int childWidthSpec;
final int horizontalMargin = lp.leftMargin + lp.rightMargin;
if (lp.width == LayoutParams.WRAP_CONTENT) {
childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
MeasureSpec.AT_MOST);
} else if (lp.width == LayoutParams.FILL_PARENT) {
childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
MeasureSpec.EXACTLY);
} else {
childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
}
int childHeightSpec;
if (lp.height == LayoutParams.WRAP_CONTENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST);
} else if (lp.height == LayoutParams.FILL_PARENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
}
child.measure(childWidthSpec, childHeightSpec);
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
if (heightMode == MeasureSpec.AT_MOST && childHeight > layoutHeight) {
layoutHeight = Math.min(childHeight, maxLayoutHeight);
}
widthRemaining -= childWidth;
canSlide |= lp.slideable = widthRemaining < 0;
if (lp.slideable) {
mSlideableView = child;
}
}
// Resolve weight and make sure non-sliding panels are smaller than the full screen.
if (canSlide || weightSum > 0) {
final int fixedPanelWidthLimit = widthAvailable - mOverhangSize;
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (child.getVisibility() == GONE) {
continue;
}
final boolean skippedFirstPass = lp.width == 0 && lp.weight > 0;
final int measuredWidth = skippedFirstPass ? 0 : child.getMeasuredWidth();
if (canSlide && child != mSlideableView) {
if (lp.width < 0 && (measuredWidth > fixedPanelWidthLimit || lp.weight > 0)) {
// Fixed panels in a sliding configuration should
// be clamped to the fixed panel limit.
final int childHeightSpec;
if (skippedFirstPass) {
// Do initial height measurement if we skipped measuring this view
// the first time around.
if (lp.height == LayoutParams.WRAP_CONTENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
MeasureSpec.AT_MOST);
} else if (lp.height == LayoutParams.FILL_PARENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
MeasureSpec.EXACTLY);
}
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(
child.getMeasuredHeight(), MeasureSpec.EXACTLY);
}
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
fixedPanelWidthLimit, MeasureSpec.EXACTLY);
child.measure(childWidthSpec, childHeightSpec);
}
} else if (lp.weight > 0) {
int childHeightSpec;
if (lp.width == 0) {
// This was skipped the first time; figure out a real height spec.
if (lp.height == LayoutParams.WRAP_CONTENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
MeasureSpec.AT_MOST);
} else if (lp.height == LayoutParams.FILL_PARENT) {
childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
MeasureSpec.EXACTLY);
}
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(
child.getMeasuredHeight(), MeasureSpec.EXACTLY);
}
if (canSlide) {
// Consume available space
final int horizontalMargin = lp.leftMargin + lp.rightMargin;
final int newWidth = widthAvailable - horizontalMargin;
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
newWidth, MeasureSpec.EXACTLY);
if (measuredWidth != newWidth) {
child.measure(childWidthSpec, childHeightSpec);
}
} else {
// Distribute the extra width proportionally similar to LinearLayout
final int widthToDistribute = Math.max(0, widthRemaining);
final int addedWidth = (int) (lp.weight * widthToDistribute / weightSum);
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
measuredWidth + addedWidth, MeasureSpec.EXACTLY);
child.measure(childWidthSpec, childHeightSpec);
}
}
}
}
final int measuredWidth = widthSize;
final int measuredHeight = layoutHeight + getPaddingTop() + getPaddingBottom();
setMeasuredDimension(measuredWidth, measuredHeight);
mCanSlide = canSlide;
if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && !canSlide) {
// Cancel scrolling in progress, it's no longer relevant.
mDragHelper.abort();
}
|
private void | onPanelDragged(int newLeft)
if (mSlideableView == null) {
// This can happen if we're aborting motion during layout because everything now fits.
mSlideOffset = 0;
return;
}
final boolean isLayoutRtl = isLayoutRtlSupport();
final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
int childWidth = mSlideableView.getWidth();
final int newStart = isLayoutRtl ? getWidth() - newLeft - childWidth : newLeft;
final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
final int startBound = paddingStart + lpMargin;
mSlideOffset = (float) (newStart - startBound) / mSlideRange;
if (mParallaxBy != 0) {
parallaxOtherViews(mSlideOffset);
}
if (lp.dimWhenOffset) {
dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
}
dispatchOnPanelSlide(mSlideableView);
|
protected void | onRestoreInstanceState(android.os.Parcelable state)
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
if (ss.isOpen) {
openPane();
} else {
closePane();
}
mPreservedOpenState = ss.isOpen;
|
protected android.os.Parcelable | onSaveInstanceState()
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.isOpen = isSlideable() ? isOpen() : mPreservedOpenState;
return ss;
|
protected void | onSizeChanged(int w, int h, int oldw, int oldh)
super.onSizeChanged(w, h, oldw, oldh);
// Recalculate sliding panes and their details
if (w != oldw) {
mFirstLayout = true;
}
|
public boolean | onTouchEvent(android.view.MotionEvent ev)
if (!mCanSlide) {
return super.onTouchEvent(ev);
}
mDragHelper.processTouchEvent(ev);
final int action = ev.getAction();
boolean wantTouchEvents = true;
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mInitialMotionX = x;
mInitialMotionY = y;
break;
}
case MotionEvent.ACTION_UP: {
if (isDimmed(mSlideableView)) {
final float x = ev.getX();
final float y = ev.getY();
final float dx = x - mInitialMotionX;
final float dy = y - mInitialMotionY;
final int slop = mDragHelper.getTouchSlop();
if (dx * dx + dy * dy < slop * slop &&
mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y)) {
// Taps close a dimmed open pane.
closePane(mSlideableView, 0);
break;
}
}
break;
}
}
return wantTouchEvents;
|
private boolean | openPane(android.view.View pane, int initialVelocity)
if (mFirstLayout || smoothSlideTo(1.f, initialVelocity)) {
mPreservedOpenState = true;
return true;
}
return false;
|
public boolean | openPane()Open the sliding pane if it is currently slideable. If first layout
has already completed this will animate.
return openPane(mSlideableView, 0);
|
private void | parallaxOtherViews(float slideOffset)
final boolean isLayoutRtl = isLayoutRtlSupport();
final LayoutParams slideLp = (LayoutParams) mSlideableView.getLayoutParams();
final boolean dimViews = slideLp.dimWhenOffset &&
(isLayoutRtl ? slideLp.rightMargin : slideLp.leftMargin) <= 0;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
if (v == mSlideableView) continue;
final int oldOffset = (int) ((1 - mParallaxOffset) * mParallaxBy);
mParallaxOffset = slideOffset;
final int newOffset = (int) ((1 - slideOffset) * mParallaxBy);
final int dx = oldOffset - newOffset;
v.offsetLeftAndRight(isLayoutRtl ? -dx : dx);
if (dimViews) {
dimChildView(v, isLayoutRtl ? mParallaxOffset - 1 :
1 - mParallaxOffset, mCoveredFadeColor);
}
}
|
public void | requestChildFocus(android.view.View child, android.view.View focused)
super.requestChildFocus(child, focused);
if (!isInTouchMode() && !mCanSlide) {
mPreservedOpenState = child == mSlideableView;
}
|
void | setAllChildrenVisible()
for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == INVISIBLE) {
child.setVisibility(VISIBLE);
}
}
|
public void | setCoveredFadeColor(int color)Set the color used to fade the pane covered by the sliding pane out when the pane
will become fully covered in the closed state.
mCoveredFadeColor = color;
|
public void | setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout$PanelSlideListener listener)
mPanelSlideListener = listener;
|
public void | setParallaxDistance(int parallaxBy)Set a distance to parallax the lower pane by when the upper pane is in its
fully closed state. The lower pane will scroll between this position and
its fully open state.
mParallaxBy = parallaxBy;
requestLayout();
|
public void | setShadowDrawable(android.graphics.drawable.Drawable d)
setShadowDrawableLeft(d);
|
public void | setShadowDrawableLeft(android.graphics.drawable.Drawable d)Set a drawable to use as a shadow cast by the right pane onto the left pane
during opening/closing.
mShadowDrawableLeft = d;
|
public void | setShadowDrawableRight(android.graphics.drawable.Drawable d)Set a drawable to use as a shadow cast by the left pane onto the right pane
during opening/closing to support right to left language.
mShadowDrawableRight = d;
|
public void | setShadowResource(int resId)Set a drawable to use as a shadow cast by the right pane onto the left pane
during opening/closing.
setShadowDrawable(getResources().getDrawable(resId));
|
public void | setShadowResourceLeft(int resId)Set a drawable to use as a shadow cast by the right pane onto the left pane
during opening/closing.
setShadowDrawableLeft(getResources().getDrawable(resId));
|
public void | setShadowResourceRight(int resId)Set a drawable to use as a shadow cast by the left pane onto the right pane
during opening/closing to support right to left language.
setShadowDrawableRight(getResources().getDrawable(resId));
|
public void | setSliderFadeColor(int color)Set the color used to fade the sliding pane out when it is slid most of the way offscreen.
mSliderFadeColor = color;
|
public void | smoothSlideClosed()
closePane();
|
public void | smoothSlideOpen()
openPane();
|
boolean | smoothSlideTo(float slideOffset, int velocity)Smoothly animate mDraggingPane to the target X position within its range.
if (!mCanSlide) {
// Nothing to do.
return false;
}
final boolean isLayoutRtl = isLayoutRtlSupport();
final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
int x;
if (isLayoutRtl) {
int startBound = getPaddingRight() + lp.rightMargin;
int childWidth = mSlideableView.getWidth();
x = (int) (getWidth() - (startBound + slideOffset * mSlideRange + childWidth));
} else {
int startBound = getPaddingLeft() + lp.leftMargin;
x = (int) (startBound + slideOffset * mSlideRange);
}
if (mDragHelper.smoothSlideViewTo(mSlideableView, x, mSlideableView.getTop())) {
setAllChildrenVisible();
ViewCompat.postInvalidateOnAnimation(this);
return true;
}
return false;
|
void | updateObscuredViewsVisibility(android.view.View panel)
final boolean isLayoutRtl = isLayoutRtlSupport();
final int startBound = isLayoutRtl ? (getWidth() - getPaddingRight()) :
getPaddingLeft();
final int endBound = isLayoutRtl ? getPaddingLeft() :
(getWidth() - getPaddingRight());
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - getPaddingBottom();
final int left;
final int right;
final int top;
final int bottom;
if (panel != null && viewIsOpaque(panel)) {
left = panel.getLeft();
right = panel.getRight();
top = panel.getTop();
bottom = panel.getBottom();
} else {
left = right = top = bottom = 0;
}
for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
final View child = getChildAt(i);
if (child == panel) {
// There are still more children above the panel but they won't be affected.
break;
}
final int clampedChildLeft = Math.max((isLayoutRtl ? endBound :
startBound), child.getLeft());
final int clampedChildTop = Math.max(topBound, child.getTop());
final int clampedChildRight = Math.min((isLayoutRtl ? startBound :
endBound), 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);
}
|
private static boolean | viewIsOpaque(android.view.View v)
if (ViewCompat.isOpaque(v)) return true;
// View#isOpaque didn't take all valid opaque scrollbar modes into account
// before API 18 (JB-MR2). On newer devices rely solely on isOpaque above and return false
// here. On older devices, check the view's background drawable directly as a fallback.
if (Build.VERSION.SDK_INT >= 18) return false;
final Drawable bg = v.getBackground();
if (bg != null) {
return bg.getOpacity() == PixelFormat.OPAQUE;
}
return false;
|