Ab Android 12 (API-Level 31) können Sie
RoundedCorner
und
Sie erhalten WindowInsets.getRoundedCorner(int
position)
Radius und Mittelpunkt für abgerundete Ecken des Gerätebildschirms Diese APIs
Du kannst verhindern, dass die UI-Elemente deiner App auf Bildschirmen mit abgerundeten Ecken abgeschnitten werden.
Ecken. Das Framework liefert
getPrivacyIndicatorBounds()
API, die das Bounded Rectangle jedes sichtbaren Mikrofons und der Kamera zurückgibt
Indikatoren.
Wenn diese APIs in Ihrer App implementiert sind, haben sie keine Auswirkungen auf Geräte mit nicht gerundete Bildschirme.
<ph type="x-smartling-placeholder">Rufen Sie zum Implementieren dieser Funktion die RoundedCorner
-Informationen mit
WindowInsets.getRoundedCorner(int position)
relativ zu den Grenzen der
. Wenn die App nicht den gesamten Bildschirm einnimmt, wendet die API die
abgerundete Ecke, indem Sie den Mittelpunkt der abgerundeten Ecke auf das Fenster stützen
Grenzen der App festlegen.
Das folgende Code-Snippet zeigt, wie eine App verhindern kann, dass ihre Benutzeroberfläche durch
Sie legen einen Rand der Ansicht basierend auf den Informationen von RoundedCorner
fest. In dieser
ist es die abgerundete Ecke oben rechts.
Kotlin
// Get the top-right rounded corner from WindowInsets. val insets = rootWindowInsets val topRight = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT) ?: return // Get the location of the close button in window coordinates. val location = IntArray(2) closeButton!!.getLocationInWindow(location) val buttonRightInWindow = location[0] + closeButton.width val buttonTopInWindow = location[1] // Find the point on the quarter circle with a 45-degree angle. val offset = (topRight.radius * Math.sin(Math.toRadians(45.0))).toInt() val topBoundary = topRight.center.y - offset val rightBoundary = topRight.center.x + offset // Check whether the close button exceeds the boundary. if (buttonRightInWindow < rightBoundary << buttonTopInWindow > topBoundary) { return } // Set the margin to avoid truncating. val parentLocation = IntArray(2) getLocationInWindow(parentLocation) val lp = closeButton.layoutParams as FrameLayout.LayoutParams lp.rightMargin = Math.max(buttonRightInWindow - rightBoundary, 0) lp.topMargin = Math.max(topBoundary - buttonTopInWindow, 0) closeButton.layoutParams = lp
Java
// Get the top-right rounded corner from WindowInsets. final WindowInsets insets = getRootWindowInsets(); final RoundedCorner topRight = insets.getRoundedCorner(POSITION_TOP_RIGHT); if (topRight == null) { return; } // Get the location of the close button in window coordinates. int [] location = new int[2]; closeButton.getLocationInWindow(location); final int buttonRightInWindow = location[0] + closeButton.getWidth(); final int buttonTopInWindow = location[1]; // Find the point on the quarter circle with a 45-degree angle. final int offset = (int) (topRight.getRadius() * Math.sin(Math.toRadians(45))); final int topBoundary = topRight.getCenter().y - offset; final int rightBoundary = topRight.getCenter().x + offset; // Check whether the close button exceeds the boundary. if (buttonRightInWindow < rightBoundary << buttonTopInWindow > topBoundary) { return; } // Set the margin to avoid truncating. int [] parentLocation = new int[2]; getLocationInWindow(parentLocation); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) closeButton.getLayoutParams(); lp.rightMargin = Math.max(buttonRightInWindow - rightBoundary, 0); lp.topMargin = Math.max(topBoundary - buttonTopInWindow, 0); closeButton.setLayoutParams(lp);
Achten Sie darauf,
Wenn Ihre Benutzeroberfläche den gesamten Bildschirm ausfüllt, können abgerundete Ecken Probleme mit Inhalten verursachen. zu beschneiden. Abbildung 2 zeigt beispielsweise ein Symbol in der Ecke des Displays mit das Layout hinter den Systemleisten:
<ph type="x-smartling-placeholder">Um dies zu vermeiden, achten Sie auf abgerundete Ecken und verwenden Sie Innenabstände, Ihre App-Inhalte aus den Ecken des Geräts zu übertragen, wie im Folgenden Beispiel:
Kotlin
class InsetsLayout(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { val insets = rootWindowInsets if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && insets != null) { applyRoundedCornerPadding(insets) } super.onLayout(changed, left, top, right, bottom) } @RequiresApi(Build.VERSION_CODES.S) private fun applyRoundedCornerPadding(insets: WindowInsets) { val topLeft = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT) val topRight = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT) val bottomLeft = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT) val bottomRight = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT) val leftRadius = max(topLeft?.radius ?: 0, bottomLeft?.radius ?: 0) val topRadius = max(topLeft?.radius ?: 0, topRight?.radius ?: 0) val rightRadius = max(topRight?.radius ?: 0, bottomRight?.radius ?: 0) val bottomRadius = max(bottomLeft?.radius ?: 0, bottomRight?.radius ?: 0) val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val windowBounds = windowManager.currentWindowMetrics.bounds val safeArea = Rect( windowBounds.left + leftRadius, windowBounds.top + topRadius, windowBounds.right - rightRadius, windowBounds.bottom - bottomRadius ) val location = intArrayOf(0, 0) getLocationInWindow(location) val leftMargin = location[0] - windowBounds.left val topMargin = location[1] - windowBounds.top val rightMargin = windowBounds.right - right - location[0] val bottomMargin = windowBounds.bottom - bottom - location[1] val layoutBounds = Rect( location[0] + paddingLeft, location[1] + paddingTop, location[0] + width - paddingRight, location[1] + height - paddingBottom ) if (layoutBounds != safeArea && layoutBounds.contains(safeArea)) { setPadding( calculatePadding(leftRadius, leftMargin, paddingLeft), calculatePadding(topRadius, topMargin, paddingTop), calculatePadding(rightRadius, rightMargin, paddingRight), calculatePadding(bottomRadius, bottomMargin, paddingBottom) ) } } private fun calculatePadding(radius1: Int?, radius2: Int?, margin: Int, padding: Int): Int = (max(radius1 ?: 0, radius2 ?: 0) - margin - padding).coerceAtLeast(0) }
Java
public class InsetsLayout extends FrameLayout { public InsetsLayout(@NonNull Context context) { super(context); } public InsetsLayout(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { WindowInsets insets = getRootWindowInsets(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && insets != null) { applyRoundedCornerPadding(insets); } super.onLayout(changed, left, top, right, bottom); } @RequiresApi(Build.VERSION_CODES.S) private void applyRoundedCornerPadding(WindowInsets insets) { RoundedCorner topLeft = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT); RoundedCorner topRight = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT); RoundedCorner bottomLeft = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT); RoundedCorner bottomRight = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT); int radiusTopLeft = 0; int radiusTopRight = 0; int radiusBottomLeft = 0; int radiusBottomRight = 0; if (topLeft != null) radiusTopLeft = topLeft.getRadius(); if (topRight != null) radiusTopRight = topRight.getRadius(); if (bottomLeft != null) radiusBottomLeft = bottomLeft.getRadius(); if (bottomRight != null) radiusBottomRight = bottomRight.getRadius(); int leftRadius = Math.max(radiusTopLeft, radiusBottomLeft); int topRadius = Math.max(radiusTopLeft, radiusTopRight); int rightRadius = Math.max(radiusTopRight, radiusBottomRight); int bottomRadius = Math.max(radiusBottomLeft, radiusBottomRight); WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); Rect safeArea = new Rect( windowBounds.left + leftRadius, windowBounds.top + topRadius, windowBounds.right - rightRadius, windowBounds.bottom - bottomRadius ); int[] location = {0, 0}; getLocationInWindow(location); int leftMargin = location[0] - windowBounds.left; int topMargin = location[1] - windowBounds.top; int rightMargin = windowBounds.right - getRight() - location[0]; int bottomMargin = windowBounds.bottom - getBottom() - location[1]; Rect layoutBounds = new Rect( location[0] + getPaddingLeft(), location[1] + getPaddingTop(), location[0] + getWidth() - getPaddingRight(), location[1] + getHeight() - getPaddingBottom() ); if (!layoutBounds.equals(safeArea) && layoutBounds.contains(safeArea)) { setPadding( calculatePadding(radiusTopLeft, radiusBottomLeft, leftMargin, getPaddingLeft()), calculatePadding(radiusTopLeft, radiusTopRight, topMargin, getPaddingTop()), calculatePadding(radiusTopRight, radiusBottomRight, rightMargin, getPaddingRight()), calculatePadding(radiusBottomLeft, radiusBottomRight, bottomMargin, getPaddingBottom()) ); } } private int calculatePadding(int radius1, int radius2, int margin, int padding) { return Math.max(Math.max(radius1, radius2) - margin - padding, 0); } }
Mit diesem Layout wird festgelegt, ob sich die Benutzeroberfläche auf den Bereich der abgerundeten Ecken erstreckt und fügt dort, wo es kommt, einen Abstand hinzu. Abbildung 3 zeigt die Layoutgrenzen anzeigen. Entwickler aktiviert, um den angewendeten Abstand deutlicher darzustellen:
<ph type="x-smartling-placeholder">Dazu berechnet das Layout zwei Rechtecke: safeArea
ist
die Fläche innerhalb der Radien der abgerundeten Ecken und layoutBounds
ist die Größe
des Layouts abzüglich der Abstände. Wenn layoutArea
safeArea
vollständig enthält, dann:
werden die untergeordneten Elemente
des Layouts möglicherweise abgeschnitten. In diesem Fall wird der Abstand
wurde hinzugefügt, damit das Layout weiterhin innerhalb von safeArea
verbleibt.
Wenn Sie prüfen, ob layoutBounds
safeArea
vollständig enthält, vermeiden Sie es,
Abstand, wenn sich das Layout nicht bis zum Rand des Bildschirms erstreckt. Abbildung 4
zeigt das Layout an, wenn es nicht hinter der Navigationsleiste gezeichnet ist. In diesem Fall
erweitert sich das Layout nicht weit genug nach unten, um sich innerhalb der abgerundeten Ecken zu befinden,
sie in den Bereich der Navigationsleiste passen. Ein Abstand ist nicht erforderlich.