You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
There are many Widgets extending FrameLayout and adding custom behaviour on top. For example NavigationView. This didn't realy work with our custom implementation
387 lines
14 KiB
Java
387 lines
14 KiB
Java
/*
|
|
* Copyright (C) 2006 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.widget;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.TypedArray;
|
|
import android.util.AttributeSet;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import com.android.internal.R;
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* FrameLayout is designed to block out an area on the screen to display
|
|
* a single item. Generally, FrameLayout should be used to hold a single child view, because it can
|
|
* be difficult to organize child views in a way that's scalable to different screen sizes without
|
|
* the children overlapping each other. You can, however, add multiple children to a FrameLayout
|
|
* and control their position within the FrameLayout by assigning gravity to each child, using the
|
|
* <a href="FrameLayout.LayoutParams.html#attr_android:layout_gravity">{@code
|
|
* android:layout_gravity}</a> attribute.
|
|
* <p>Child views are drawn in a stack, with the most recently added child on top.
|
|
* The size of the FrameLayout is the size of its largest child (plus padding), visible
|
|
* or not (if the FrameLayout's parent permits). Views that are {@link android.view.View#GONE} are
|
|
* used for sizing
|
|
* only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
|
|
* is set to true.
|
|
*
|
|
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
|
|
*/
|
|
public class FrameLayout extends ViewGroup {
|
|
private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START;
|
|
boolean mMeasureAllChildren = false;
|
|
// private int mForegroundPaddingLeft = 0;
|
|
// private int mForegroundPaddingTop = 0;
|
|
// private int mForegroundPaddingRight = 0;
|
|
// private int mForegroundPaddingBottom = 0;
|
|
private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
|
|
|
|
public FrameLayout(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
public FrameLayout(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public FrameLayout(Context context, AttributeSet attrs,
|
|
int defStyleAttr) {
|
|
this(context, attrs, defStyleAttr, 0);
|
|
}
|
|
|
|
public FrameLayout(Context context, AttributeSet attrs,
|
|
int defStyleAttr, int defStyleRes) {
|
|
super(context, attrs, defStyleAttr, defStyleRes);
|
|
final TypedArray a = context.obtainStyledAttributes(
|
|
attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
|
|
// saveAttributeDataForStyleable(context, R.styleable.FrameLayout,
|
|
// attrs, a, defStyleAttr, defStyleRes);
|
|
if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
|
|
setMeasureAllChildren(true);
|
|
}
|
|
a.recycle();
|
|
}
|
|
|
|
/**
|
|
* Returns a set of layout parameters with a width of
|
|
* {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
|
|
* and a height of {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}.
|
|
*/
|
|
@Override
|
|
protected LayoutParams generateDefaultLayoutParams() {
|
|
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
|
}
|
|
|
|
int getPaddingLeftWithForeground() {
|
|
// return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
|
|
// mPaddingLeft + mForegroundPaddingLeft;
|
|
return 0;
|
|
}
|
|
|
|
int getPaddingRightWithForeground() {
|
|
// return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) :
|
|
// mPaddingRight + mForegroundPaddingRight;
|
|
return 0;
|
|
}
|
|
|
|
private int getPaddingTopWithForeground() {
|
|
// return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) :
|
|
// mPaddingTop + mForegroundPaddingTop;
|
|
return 0;
|
|
}
|
|
|
|
private int getPaddingBottomWithForeground() {
|
|
// return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
|
|
// mPaddingBottom + mForegroundPaddingBottom;
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
int count = getChildCount();
|
|
final boolean measureMatchParentChildren =
|
|
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
|
|
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
|
|
mMatchParentChildren.clear();
|
|
int maxHeight = 0;
|
|
int maxWidth = 0;
|
|
int childState = 0;
|
|
for (int i = 0; i < count; i++) {
|
|
final View child = getChildAt(i);
|
|
if (mMeasureAllChildren || child.getVisibility() != GONE) {
|
|
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
|
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
|
maxWidth = Math.max(maxWidth,
|
|
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
|
|
maxHeight = Math.max(maxHeight,
|
|
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
|
|
childState = combineMeasuredStates(childState, child.getMeasuredState());
|
|
if (measureMatchParentChildren) {
|
|
if (lp.width == LayoutParams.MATCH_PARENT ||
|
|
lp.height == LayoutParams.MATCH_PARENT) {
|
|
mMatchParentChildren.add(child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Account for padding too
|
|
maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
|
|
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
|
|
// Check against our minimum height and width
|
|
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
|
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
|
// Check against our foreground's minimum height and width
|
|
// final Drawable drawable = getForeground();
|
|
// if (drawable != null) {
|
|
// maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
|
|
// maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
|
|
// }
|
|
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
|
|
resolveSizeAndState(maxHeight, heightMeasureSpec,
|
|
childState << MEASURED_HEIGHT_STATE_SHIFT));
|
|
count = mMatchParentChildren.size();
|
|
if (count > 1) {
|
|
for (int i = 0; i < count; i++) {
|
|
final View child = mMatchParentChildren.get(i);
|
|
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
|
|
final int childWidthMeasureSpec;
|
|
if (lp.width == LayoutParams.MATCH_PARENT) {
|
|
final int width = Math.max(0, getMeasuredWidth()
|
|
- getPaddingLeftWithForeground() - getPaddingRightWithForeground()
|
|
- lp.leftMargin - lp.rightMargin);
|
|
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
|
|
width, MeasureSpec.EXACTLY);
|
|
} else {
|
|
childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
|
|
getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
|
|
lp.leftMargin + lp.rightMargin,
|
|
lp.width);
|
|
}
|
|
final int childHeightMeasureSpec;
|
|
if (lp.height == LayoutParams.MATCH_PARENT) {
|
|
final int height = Math.max(0, getMeasuredHeight()
|
|
- getPaddingTopWithForeground() - getPaddingBottomWithForeground()
|
|
- lp.topMargin - lp.bottomMargin);
|
|
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
|
|
height, MeasureSpec.EXACTLY);
|
|
} else {
|
|
childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
|
|
getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
|
|
lp.topMargin + lp.bottomMargin,
|
|
lp.height);
|
|
}
|
|
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
|
|
}
|
|
|
|
void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
|
|
final int count = getChildCount();
|
|
final int parentLeft = getPaddingLeftWithForeground();
|
|
final int parentRight = right - left - getPaddingRightWithForeground();
|
|
final int parentTop = getPaddingTopWithForeground();
|
|
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
|
|
for (int i = 0; i < count; i++) {
|
|
final View child = getChildAt(i);
|
|
if (child.getVisibility() != GONE) {
|
|
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
|
final int width = child.getMeasuredWidth();
|
|
final int height = child.getMeasuredHeight();
|
|
int childLeft;
|
|
int childTop;
|
|
int gravity = lp.gravity;
|
|
if (gravity == -1) {
|
|
gravity = DEFAULT_CHILD_GRAVITY;
|
|
}
|
|
final int layoutDirection = getLayoutDirection();
|
|
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
|
|
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
|
|
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
|
|
case Gravity.CENTER_HORIZONTAL:
|
|
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
|
|
lp.leftMargin - lp.rightMargin;
|
|
break;
|
|
case Gravity.RIGHT:
|
|
if (!forceLeftGravity) {
|
|
childLeft = parentRight - width - lp.rightMargin;
|
|
break;
|
|
}
|
|
case Gravity.LEFT:
|
|
default:
|
|
childLeft = parentLeft + lp.leftMargin;
|
|
}
|
|
switch (verticalGravity) {
|
|
case Gravity.TOP:
|
|
childTop = parentTop + lp.topMargin;
|
|
break;
|
|
case Gravity.CENTER_VERTICAL:
|
|
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
|
|
lp.topMargin - lp.bottomMargin;
|
|
break;
|
|
case Gravity.BOTTOM:
|
|
childTop = parentBottom - height - lp.bottomMargin;
|
|
break;
|
|
default:
|
|
childTop = parentTop + lp.topMargin;
|
|
}
|
|
child.layout(childLeft, childTop, childLeft + width, childTop + height);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether to consider all children, or just those in
|
|
* the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
|
|
*
|
|
* @param measureAll true to consider children marked GONE, false otherwise.
|
|
* Default value is false.
|
|
*
|
|
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
|
|
*/
|
|
public void setMeasureAllChildren(boolean measureAll) {
|
|
mMeasureAllChildren = measureAll;
|
|
}
|
|
|
|
/**
|
|
* Determines whether all children, or just those in the VISIBLE or
|
|
* INVISIBLE state, are considered when measuring.
|
|
*
|
|
* @return Whether all children are considered when measuring.
|
|
*
|
|
* @deprecated This method is deprecated in favor of
|
|
* {@link #getMeasureAllChildren() getMeasureAllChildren()}, which was
|
|
* renamed for consistency with
|
|
* {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}.
|
|
*/
|
|
@Deprecated
|
|
public boolean getConsiderGoneChildrenWhenMeasuring() {
|
|
return getMeasureAllChildren();
|
|
}
|
|
|
|
/**
|
|
* Determines whether all children, or just those in the VISIBLE or
|
|
* INVISIBLE state, are considered when measuring.
|
|
*
|
|
* @return Whether all children are considered when measuring.
|
|
*/
|
|
public boolean getMeasureAllChildren() {
|
|
return mMeasureAllChildren;
|
|
}
|
|
|
|
@Override
|
|
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
|
return new FrameLayout.LayoutParams(getContext(), attrs);
|
|
}
|
|
|
|
@Override
|
|
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
|
|
return p instanceof LayoutParams;
|
|
}
|
|
|
|
@Override
|
|
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
|
|
// if (sPreserveMarginParamsInLayoutParamConversion) {
|
|
// if (lp instanceof LayoutParams) {
|
|
// return new LayoutParams((LayoutParams) lp);
|
|
// } else if (lp instanceof MarginLayoutParams) {
|
|
// return new LayoutParams((MarginLayoutParams) lp);
|
|
// }
|
|
// }
|
|
return new LayoutParams(lp);
|
|
}
|
|
|
|
/**
|
|
* Per-child layout information for layouts that support margins.
|
|
* See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
|
|
* for a list of all child view attributes that this class supports.
|
|
*
|
|
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
|
|
*/
|
|
public static class LayoutParams extends MarginLayoutParams {
|
|
/**
|
|
* Value for {@link #gravity} indicating that a gravity has not been
|
|
* explicitly specified.
|
|
*/
|
|
public static final int UNSPECIFIED_GRAVITY = -1;
|
|
|
|
/**
|
|
* The gravity to apply with the View to which these layout parameters
|
|
* are associated.
|
|
* <p>
|
|
* The default value is {@link #UNSPECIFIED_GRAVITY}, which is treated
|
|
* by FrameLayout as {@code Gravity.TOP | Gravity.START}.
|
|
*
|
|
* @see android.view.Gravity
|
|
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
|
|
*/
|
|
public int gravity = UNSPECIFIED_GRAVITY;
|
|
|
|
public LayoutParams(Context c, AttributeSet attrs) {
|
|
super(c, attrs);
|
|
final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
|
|
gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity, UNSPECIFIED_GRAVITY);
|
|
a.recycle();
|
|
}
|
|
|
|
public LayoutParams(int width, int height) {
|
|
super(width, height);
|
|
}
|
|
|
|
/**
|
|
* Creates a new set of layout parameters with the specified width, height
|
|
* and gravity.
|
|
*
|
|
* @param width the width, either {@link #MATCH_PARENT},
|
|
* {@link #WRAP_CONTENT} or a fixed size in pixels
|
|
* @param height the height, either {@link #MATCH_PARENT},
|
|
* {@link #WRAP_CONTENT} or a fixed size in pixels
|
|
* @param gravity the gravity
|
|
*
|
|
* @see android.view.Gravity
|
|
*/
|
|
public LayoutParams(int width, int height, int gravity) {
|
|
super(width, height);
|
|
this.gravity = gravity;
|
|
}
|
|
|
|
public LayoutParams(ViewGroup.LayoutParams source) {
|
|
super(source);
|
|
}
|
|
|
|
public LayoutParams(ViewGroup.MarginLayoutParams source) {
|
|
super(source);
|
|
}
|
|
|
|
/**
|
|
* Copy constructor. Clones the width, height, margin values, and
|
|
* gravity of the source.
|
|
*
|
|
* @param source The layout params to copy from.
|
|
*/
|
|
public LayoutParams(LayoutParams source) {
|
|
super(source);
|
|
this.gravity = source.gravity;
|
|
}
|
|
}
|
|
}
|