1a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/* 2a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Copyright (C) 2015 The Android Open Source Project 3a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * 4a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * you may not use this file except in compliance with the License. 6a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * You may obtain a copy of the License at 7a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * 8a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 9a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * 10a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Unless required by applicable law or agreed to in writing, software 11a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * See the License for the specific language governing permissions and 14a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * limitations under the License. 15a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */ 16a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 17a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banespackage android.support.design.widget; 18a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 1944e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banesimport android.os.Build; 20a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.v4.view.ViewCompat; 21a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.View; 22b1a51676163f8db131e6d97970459346735253beChris Banesimport android.view.ViewParent; 23a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 24a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/** 25a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Utility helper for moving a {@link android.view.View} around using 26a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@link android.view.View#offsetLeftAndRight(int)} and 27a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@link android.view.View#offsetTopAndBottom(int)}. 28a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p> 29a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Also the setting of absolute offsets (similar to translationX/Y), rather than additive 30a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * offsets. 31a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */ 32a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesclass ViewOffsetHelper { 33a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 34a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private final View mView; 35a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 36a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private int mLayoutTop; 37a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private int mLayoutLeft; 38a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private int mOffsetTop; 39a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes private int mOffsetLeft; 40a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public ViewOffsetHelper(View view) { 42a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mView = view; 43a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 44a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 45a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public void onViewLayout() { 46a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes // Now grab the intended top 47a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mLayoutTop = mView.getTop(); 48a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mLayoutLeft = mView.getLeft(); 49a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 50a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes // And offset it as needed 51a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes updateOffsets(); 52a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 53a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 54ecd4b988781330e346244be73dca39cd04c71391Chris Banes private void updateOffsets() { 55ecd4b988781330e346244be73dca39cd04c71391Chris Banes ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop)); 56ecd4b988781330e346244be73dca39cd04c71391Chris Banes ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft)); 57b1a51676163f8db131e6d97970459346735253beChris Banes 5844e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes // Manually invalidate the view and parent to make sure we get drawn pre-M 5944e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes if (Build.VERSION.SDK_INT < 23) { 6044e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes tickleInvalidationFlag(mView); 6144e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes final ViewParent vp = mView.getParent(); 6244e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes if (vp instanceof View) { 6344e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes tickleInvalidationFlag((View) vp); 6444e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes } 65a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 66a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 67a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 6844e00ab1860a78d91ad6f586f41eaae0c108a3bcChris Banes private static void tickleInvalidationFlag(View view) { 69a59da11da29af8bc9d8e07a21d68e04d6de3df92Chris Banes final float x = ViewCompat.getTranslationX(view); 70a59da11da29af8bc9d8e07a21d68e04d6de3df92Chris Banes ViewCompat.setTranslationX(view, x + 1); 71a59da11da29af8bc9d8e07a21d68e04d6de3df92Chris Banes ViewCompat.setTranslationX(view, x); 72a59da11da29af8bc9d8e07a21d68e04d6de3df92Chris Banes } 73a59da11da29af8bc9d8e07a21d68e04d6de3df92Chris Banes 74a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes /** 75a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Set the top and bottom offset for this {@link ViewOffsetHelper}'s view. 76a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * 77a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @param offset the offset in px. 78a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @return true if the offset has changed 79a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */ 80a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public boolean setTopAndBottomOffset(int offset) { 81a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (mOffsetTop != offset) { 82a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mOffsetTop = offset; 83a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes updateOffsets(); 84a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return true; 85a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 86a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return false; 87a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 88a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 89a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes /** 90a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Set the left and right offset for this {@link ViewOffsetHelper}'s view. 91a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * 92a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @param offset the offset in px. 93a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @return true if the offset has changed 94a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */ 95a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public boolean setLeftAndRightOffset(int offset) { 96a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes if (mOffsetLeft != offset) { 97a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes mOffsetLeft = offset; 98a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes updateOffsets(); 99a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return true; 100a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 101a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return false; 102a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 103a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 104a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public int getTopAndBottomOffset() { 105a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return mOffsetTop; 106a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 107a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes 108a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes public int getLeftAndRightOffset() { 109a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes return mOffsetLeft; 110a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes } 111a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes}