下面列出了android.support.v4.view.ViewCompat#offsetTopAndBottom ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void dragTo(int left, int top, int dx, int dy) {
int clampedX = left;
int clampedY = top;
final int oldLeft = mCapturedView.getLeft();
final int oldTop = mCapturedView.getTop();
if (dx != 0) {
clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);
ViewCompat.offsetLeftAndRight(mCapturedView, clampedX - oldLeft);
}
if (dy != 0) {
clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);
ViewCompat.offsetTopAndBottom(mCapturedView, clampedY - oldTop);
}
if (dx != 0 || dy != 0) {
final int clampedDx = clampedX - oldLeft;
final int clampedDy = clampedY - oldTop;
mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY,
clampedDx, clampedDy);
}
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
int dy, int[] consumed) {
View scrollingChild = mNestedScrollingChildRef.get();
if (target != scrollingChild) {
return;
}
int currentTop = child.getTop();
int newTop = currentTop - dy;
if (dy > 0) { // Upward
if (newTop < mMinOffset) {
consumed[1] = currentTop - mMinOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_EXPANDED);
} else {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
}
} else if (dy < 0) { // Downward
if (!target.canScrollVertically(-1)) {
if (newTop <= mMaxOffset || mHideable) {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
} else {
consumed[1] = currentTop - mMaxOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_COLLAPSED);
}
}
}
dispatchOnSlide(child.getTop());
mLastNestedScrollDy = dy;
mNestedScrolled = true;
}
public 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(3);
} else {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
this.setStateInternal(1);
}
} 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(4);
} else {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
this.setStateInternal(1);
}
}
this.dispatchOnSlide(child.getTop());
this.lastNestedScrollDy = dy;
this.nestedScrolled = true;
}
}
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.setFitsSystemWindows(child, true);
}
int savedTop = child.getTop();
// First let the parent lay it out
parent.onLayoutChild(child, layoutDirection);
// Offset the bottom sheet
mParentHeight = parent.getHeight();
int peekHeight;
if (mPeekHeightAuto) {
if (mPeekHeightMin == 0) {
mPeekHeightMin = parent.getResources().getDimensionPixelSize(
R.dimen.design_bottom_sheet_peek_height_min);
}
peekHeight = Math.max(mPeekHeightMin, mParentHeight - parent.getWidth() * 9 / 16);
} else {
peekHeight = mPeekHeight;
}
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = Math.max(mParentHeight - peekHeight, mMinOffset);
if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
} else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
return true;
}
private void updateOffsets() {
ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
// Manually invalidate the view and parent to make sure we get drawn pre-M
if (Build.VERSION.SDK_INT < 23) {
tickleInvalidationFlag(mView);
final ViewParent vp = mView.getParent();
if (vp instanceof View) {
tickleInvalidationFlag((View) vp);
}
}
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.setFitsSystemWindows(child, true);
}
int savedTop = child.getTop();
// First let the parent lay it out
parent.onLayoutChild(child, layoutDirection);
// Offset the bottom sheet
mParentHeight = parent.getHeight();
int peekHeight;
if (mPeekHeightAuto) {
if (mPeekHeightMin == 0) {
mPeekHeightMin = parent.getResources().getDimensionPixelSize(
android.support.design.R.dimen.design_bottom_sheet_peek_height_min);
}
peekHeight = Math.max(mPeekHeightMin, mParentHeight - parent.getWidth() * 9 / 16);
} else {
peekHeight = mPeekHeight;
}
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = Math.max(mParentHeight - peekHeight, mMinOffset);
if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
} else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
return true;
}
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dx,
int dy, int[] consumed) {
int currentTop = child.getTop();
int newTop = currentTop - dy;
if (dy > 0) { // Upward
if (newTop < mMinOffset) {
consumed[1] = currentTop - mMinOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_EXPANDED);
} else {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
}
} else if (dy < 0) { // Downward
if (!ViewCompat.canScrollVertically(target, -1)) {
if (newTop <= mMaxOffset || mHideable) {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
} else {
consumed[1] = currentTop - mMaxOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_COLLAPSED);
}
}
}
dispatchOnSlide(child.getTop());
mLastNestedScrollDy = dy;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
int dy, int[] consumed) {
View scrollingChild = mNestedScrollingChildRef.get();
if (target != scrollingChild) {
return;
}
int currentTop = child.getTop();
int newTop = currentTop - dy;
if (dy > 0) { // Upward
if (!ViewCompat.canScrollVertically(target, 1)) {
if (newTop >= mMinOffset || mHideable) {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
} else {
consumed[1] = currentTop - mMinOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_COLLAPSED);
}
}
} else if (dy < 0) { // Downward
// Negative to check scrolling up, positive to check scrolling down
if (newTop < mMaxOffset) {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
} else {
consumed[1] = currentTop - mMaxOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_EXPANDED);
}
}
dispatchOnSlide(child.getTop());
mLastNestedScrollDy = dy;
mNestedScrolled = true;
}
private void moveAllView(float dy) {//偏移量
int _target = (int) (targetCurrentOffset + dy);
_target = Math.max(_target, targetEndOffset);
int offset = _target - targetCurrentOffset;
ViewCompat.offsetTopAndBottom(target, offset);//最后一个视图偏移
//如果多于两个,其余也做偏移
// 但这个暂不能用,各个view偏移量需按百分比算,也需要给各个view添加上偏移位移限制
for (int i = 1; i < getChildCount() - 1; i++) {
View child = getChildAt(i);
ViewCompat.offsetTopAndBottom(child, offset / 2);
}
targetCurrentOffset = _target;
}
private void updateOffsets() {
ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
// Manually invalidate the view and parent to make sure we get drawn pre-M
if (Build.VERSION.SDK_INT < 23) {
tickleInvalidationFlag(mView);
final ViewParent vp = mView.getParent();
if (vp instanceof View) {
tickleInvalidationFlag((View) vp);
}
}
}
/**
* Move the captured settling view by the appropriate amount for the current time.
* If <code>continueSettling</code> returns true, the caller should call it again
* on the next frame to continue.
*
* @param deferCallbacks true if state callbacks should be deferred via posted message.
* Set this to true if you are calling this method from
* {@link android.view.View#computeScroll()} or similar methods
* invoked as part of layout or drawing.
* @return true if settle is still in progress
*/
public boolean continueSettling(boolean deferCallbacks) {
if (mDragState == STATE_SETTLING) {
boolean keepGoing = mScroller.computeScrollOffset();
final int x = mScroller.getCurrX();
final int y = mScroller.getCurrY();
final int dx = x - mCapturedView.getLeft();
final int dy = y - mCapturedView.getTop();
if (dx != 0) {
ViewCompat.offsetLeftAndRight(mCapturedView, dx);
}
if (dy != 0) {
ViewCompat.offsetTopAndBottom(mCapturedView, dy);
}
if (dx != 0 || dy != 0) {
mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
}
if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
// Close enough. The interpolator/scroller might think we're still moving
// but the user sure doesn't.
mScroller.abortAnimation();
keepGoing = false;
}
if (!keepGoing) {
if (deferCallbacks) {
mParentView.post(mSetIdleRunnable);
} else {
setDragState(STATE_IDLE);
}
}
}
return mDragState == STATE_SETTLING;
}
/**
* 当被监听的view发生改变时回调
* 可以在此方法里面做一些响应的联动动画等效果
*/
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
int offset = dependency.getTop() - child.getTop();
ViewCompat.offsetTopAndBottom(child, offset);
return super.onDependentViewChanged(parent, child, dependency);
}
private void updateOffsets() {
ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
// Manually invalidate the view and parent to make sure we get drawn pre-M
if (Build.VERSION.SDK_INT < 23) {
tickleInvalidationFlag(mView);
final ViewParent vp = mView.getParent();
if (vp instanceof View) {
tickleInvalidationFlag((View) vp);
}
}
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
int dy, int[] consumed) {
if (!mAllowUserDragging) {
return;
}
View scrollingChild = mNestedScrollingChildRef.get();
if (target != scrollingChild) {
return;
}
int currentTop = child.getTop();
int newTop = currentTop - dy;
if (dy > 0) { // Upward
if (newTop < mMinOffset) {
consumed[1] = currentTop - mMinOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_EXPANDED);
} else {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
}
} else if (dy < 0) { // Downward
if (!ViewCompat.canScrollVertically(target, -1)) {
if (newTop <= mMaxOffset || mHideable) {
consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -dy);
setStateInternal(STATE_DRAGGING);
} else {
consumed[1] = currentTop - mMaxOffset;
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
setStateInternal(STATE_COLLAPSED);
}
}
}
dispatchOnSlide(child.getTop());
mNestedScrolled = true;
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.setFitsSystemWindows(child, true);
}
int savedTop = child.getTop();
// First let the parent lay it out
parent.onLayoutChild(child, layoutDirection);
// Offset the bottom sheet
mParentHeight = parent.getHeight();
if (mPeekHeightAuto) {
if (mPeekHeightMin == 0) {
mPeekHeightMin = parent.getResources().getDimensionPixelSize(R.dimen.peekHeightMin);
}
mPeekHeight = mPeekHeightMin;
}
if (mAnchorHeightAuto) {
if (mAnchorHeightMin == 0) {
mAnchorHeightMin = mParentHeight - parent.getWidth() * 9 / 16;
}
mAnchorHeight = mAnchorHeightMin;
}
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset);
mAnchorOffset = Math.min(mParentHeight - mAnchorHeight, mMaxOffset);
if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
updateHeaderColor(mAnchorColor, mAnchorTextColor);
anchorViews(mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
anchorViews(mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
anchorViews(mMaxOffset);
} else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
} else if (mState == STATE_ANCHORED) {
ViewCompat.offsetTopAndBottom(child, mAnchorOffset);
updateHeaderColor(mAnchorColor, mAnchorTextColor);
if (parallax != null) {
int reference = savedTop - parallax.getHeight();
parallax.setY(reference);
parallax.setVisibility(View.VISIBLE);
anchorViews(reference);
} else {
anchorViews(mAnchorOffset);
}
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
// add missing views to the layout
ViewGroup nestedScrolling = (ViewGroup) mNestedScrollingChildRef.get();
if (nestedScrolling.getChildCount() == 0) {
nestedScrolling.addView(bottomsheet);
}
return true;
}
private void updateOffsets() {
ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
}
public void testCompat(int dis) {
ViewCompat.offsetTopAndBottom(target, dis);
}
private void moveView(View child, int dy) {
int dis = currentOffset + dy;
dis = Math.max(dis, targetOffset);
ViewCompat.offsetTopAndBottom(child, dis - currentOffset);
currentOffset = dis;
}
public void performUpdateViewPosition(int offset) {
//移动内容
ViewCompat.offsetTopAndBottom(mRefreshContainerView, -offset);
ViewCompat.offsetTopAndBottom(mRecyclerView, -offset);
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// Update the collapsed bounds by getting it's transformed bounds. This needs to be done
// before the children are offset below
if (mCollapsingTitleEnabled && mDummyView != null) {
// We only draw the title if the dummy view is being displayed (Toolbar removes
// views if there is no space)
mDrawCollapsingTitle = ViewCompat.isAttachedToWindow(mDummyView) && mDummyView.getVisibility() == VISIBLE;
if (mDrawCollapsingTitle) {
final boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
// Update the collapsed bounds
int bottomOffset = 0;
if (mToolbarDirectChild != null && mToolbarDirectChild != this) {
final LayoutParams lp = (LayoutParams) mToolbarDirectChild.getLayoutParams();
bottomOffset = lp.bottomMargin;
}
ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
mCollapsingTextHelper.setCollapsedBounds(
mTmpRect.left + (isRtl ? mToolbar.getTitleMarginEnd() : mToolbar.getTitleMarginStart()),
bottom + mToolbar.getTitleMarginTop() - mTmpRect.height() - bottomOffset,
mTmpRect.right + (isRtl ? mToolbar.getTitleMarginStart() : mToolbar.getTitleMarginEnd()),
bottom - bottomOffset - mToolbar.getTitleMarginBottom());
// Update the expanded bounds
mCollapsingTextHelper.setExpandedBounds(
isRtl ? mExpandedMarginEnd : mExpandedMarginStart,
mTmpRect.bottom + mExpandedMarginTop,
right - left - (isRtl ? mExpandedMarginStart : mExpandedMarginEnd),
bottom - top - mExpandedMarginBottom);
// Now recalculate using the new bounds
mCollapsingTextHelper.recalculate();
}
}
// Update our child view offset helpers
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
if (mLastInsets != null && !ViewCompat.getFitsSystemWindows(child)) {
final int insetTop = mLastInsets.getSystemWindowInsetTop();
if (child.getTop() < insetTop) {
// If the child isn't set to fit system windows but is drawing within the inset
// offset it down
ViewCompat.offsetTopAndBottom(child, insetTop);
}
}
getViewOffsetHelper(child).onViewLayout();
}
// Finally, set our minimum height to enable proper AppBarLayout collapsing
if (mToolbar != null) {
if (mCollapsingTitleEnabled && TextUtils.isEmpty(mCollapsingTextHelper.getText())) {
// If we do not currently have a title, try and grab it from the Toolbar
mCollapsingTextHelper.setText(mToolbar.getTitle());
}
if (mToolbarDirectChild == null || mToolbarDirectChild == this) {
setMinimumHeight(getHeightWithMargins(mToolbar));
} else {
setMinimumHeight(getHeightWithMargins(mToolbarDirectChild));
}
}
}