Created
February 9, 2024 12:30
-
-
Save entdark/88dfb3dcb7b0065cced4555b62162f0e to your computer and use it in GitHub Desktop.
.NET Android MvvmCross SystemBars Insets (SafeArea) XML injector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="View"> | |
<attr name="paddingLeftFitsWindowInsets" format="boolean"/> | |
<attr name="paddingRightFitsWindowInsets" format="boolean"/> | |
<attr name="paddingTopFitsWindowInsets" format="boolean"/> | |
<attr name="paddingBottomFitsWindowInsets" format="boolean"/> | |
<attr name="marginLeftFitsWindowInsets" format="boolean"/> | |
<attr name="marginRightFitsWindowInsets" format="boolean"/> | |
<attr name="marginTopFitsWindowInsets" format="boolean"/> | |
<attr name="marginBottomFitsWindowInsets" format="boolean"/> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Android.OS; | |
using Google.Android.Material.Internal; | |
using MvvmCross.Platforms.Android.Views; | |
namespace APP_NAMESPACE; | |
public class HostActivityExample : MvxActivity { | |
protected override void OnCreate(Bundle savedInstanceState) { | |
base.OnCreate(savedInstanceState); | |
var view = this.BindingInflate(Resource.Layout.page_example, null); | |
SetContentView(view); | |
EdgeToEdgeUtils.ApplyEdgeToEdge(this.Window, true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
tools:text="Text" | |
android:textColor="?attr/colorOnSurface" | |
android:textAppearance="?attr/textAppearanceBodyLarge" | |
android:layout_width="match_parent" | |
android:layout_height="48dp" | |
android:paddingLeft="16dp" | |
android:paddingRight="24dp" | |
android:foreground="?android:attr/selectableItemBackground" | |
app:paddingLeftFitsWindowInsets="true" | |
app:paddingRightFitsWindowInsets="true" | |
app:MvxBind="Text Title; Checked IsChecked"/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="?android:attr/colorBackground"> | |
<com.google.android.material.appbar.AppBarLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
app:liftOnScrollTargetViewId="@id/mvxrecyclerview" | |
app:paddingLeftFitsWindowInsets="true" | |
app:paddingRightFitsWindowInsets="true" | |
app:paddingTopFitsWindowInsets="true"> | |
<include layout="@layout/toolbar"/> | |
</com.google.android.material.appbar.AppBarLayout> | |
<mvvmcross.droidx.recyclerview.MvxRecyclerView | |
android:id="@+id/mvxrecyclerview" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:clipToPadding="false" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:paddingBottomFitsWindowInsets="true" | |
app:MvxItemTemplate="@layout/item_example" | |
app:MvxBind="ItemsSource Items; ItemClick ItemClickCommand"/> | |
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Android.Content; | |
using Android.Views; | |
using AndroidX.Core.View; | |
using Google.Android.Material.Internal; | |
using MvvmCross.Binding; | |
using MvvmCross.Platforms.Android.Binding; | |
using MvvmCross.Platforms.Android.Binding.Binders; | |
using MvvmCross.Platforms.Android.Core; | |
namespace APP_NAMESPACE; | |
public class Setup : MvxAndroidSetup<App> { | |
protected override MvxBindingBuilder CreateBindingBuilder() { | |
return new InsetsAndroidBindingBuilder(); | |
} | |
private class InsetsAndroidBindingBuilder : MvxAndroidBindingBuilder { | |
protected override IMvxLayoutInflaterHolderFactoryFactory CreateLayoutInflaterFactoryFactory() { | |
return new InsetsLayoutInflaterFactoryFactory(); | |
} | |
private class InsetsLayoutInflaterFactoryFactory : IMvxLayoutInflaterHolderFactoryFactory { | |
public IMvxLayoutInflaterHolderFactory Create(object source) { | |
return new InsetsBindingLayoutInflaterFactory(source); | |
} | |
private class InsetsBindingLayoutInflaterFactory : MvxBindingLayoutInflaterFactory { | |
public InsetsBindingLayoutInflaterFactory(object source) : base(source) { | |
} | |
public override View BindCreatedView(View view, Context context, global::Android.Util.IAttributeSet attrs) { | |
using var typedArray = context.ObtainStyledAttributes(attrs, Resource.Styleable.View); | |
int numStyles = typedArray.IndexCount; | |
var flags = WindowInsetsFlags.None; | |
for (var i = 0; i < numStyles; ++i) { | |
var attributeId = typedArray.GetIndex(i); | |
bool attributeValue = typedArray.GetBoolean(attributeId, false); | |
if (attributeValue) { | |
flags |= attributeId switch { | |
Resource.Styleable.View_paddingLeftFitsWindowInsets => WindowInsetsFlags.PaddingLeft, | |
Resource.Styleable.View_paddingRightFitsWindowInsets => WindowInsetsFlags.PaddingRight, | |
Resource.Styleable.View_paddingTopFitsWindowInsets => WindowInsetsFlags.PaddingTop, | |
Resource.Styleable.View_paddingBottomFitsWindowInsets => WindowInsetsFlags.PaddingBottom, | |
Resource.Styleable.View_marginLeftFitsWindowInsets => WindowInsetsFlags.MarginLeft, | |
Resource.Styleable.View_marginRightFitsWindowInsets => WindowInsetsFlags.MarginRight, | |
Resource.Styleable.View_marginTopFitsWindowInsets => WindowInsetsFlags.MarginTop, | |
Resource.Styleable.View_marginBottomFitsWindowInsets => WindowInsetsFlags.MarginBottom, | |
_ => WindowInsetsFlags.None | |
}; | |
} | |
} | |
if (flags != WindowInsetsFlags.None) | |
ViewUtils.DoOnApplyWindowInsets(view, new OnApplyWindowInsetsListener(flags)); | |
typedArray.Recycle(); | |
return base.BindCreatedView(view, context, attrs); | |
} | |
} | |
} | |
private class OnApplyWindowInsetsListener : Java.Lang.Object, ViewUtils.IOnApplyWindowInsetsListener { | |
private readonly WindowInsetsFlags flags; | |
private ViewGroup.MarginLayoutParams initialLayoutParameters; | |
public OnApplyWindowInsetsListener(WindowInsetsFlags flags) { | |
this.flags = flags; | |
} | |
public WindowInsetsCompat OnApplyWindowInsets(View view, WindowInsetsCompat insetsCompat, ViewUtils.RelativePadding initialPadding) { | |
bool paddingTop = flags.HasFlag(WindowInsetsFlags.PaddingTop); | |
bool paddingBottom = flags.HasFlag(WindowInsetsFlags.PaddingBottom); | |
bool paddingLeft = flags.HasFlag(WindowInsetsFlags.PaddingLeft); | |
bool paddingRight = flags.HasFlag(WindowInsetsFlags.PaddingRight); | |
var insets = insetsCompat.GetInsets(WindowInsetsCompat.Type.SystemBars()); | |
int insetTop = insets.Top; | |
int insetBottom = insets.Bottom; | |
int insetLeft = insets.Left; | |
int insetRight = insets.Right; | |
bool isRtl = ViewCompat.GetLayoutDirection(view) == ViewCompat.LayoutDirectionRtl; | |
initialPadding.Top += paddingTop ? insetTop : 0; | |
initialPadding.Bottom += paddingBottom ? insetBottom : 0; | |
int systemWindowInsetLeft = paddingLeft ? insetLeft : 0; | |
int systemWindowInsetRight = paddingRight ? insetRight : 0; | |
initialPadding.Start += isRtl ? systemWindowInsetRight : systemWindowInsetLeft; | |
initialPadding.End += isRtl ? systemWindowInsetLeft : systemWindowInsetRight; | |
initialPadding.ApplyToView(view); | |
if (view.LayoutParameters is ViewGroup.MarginLayoutParams marginLayoutParameters && initialLayoutParameters == null) { | |
initialLayoutParameters = new ViewGroup.MarginLayoutParams(marginLayoutParameters); | |
} | |
if (initialLayoutParameters != null) { | |
bool marginTop = flags.HasFlag(WindowInsetsFlags.MarginTop); | |
bool marginBottom = flags.HasFlag(WindowInsetsFlags.MarginBottom); | |
bool marginLeft = flags.HasFlag(WindowInsetsFlags.MarginLeft); | |
bool marginRight = flags.HasFlag(WindowInsetsFlags.MarginRight); | |
if (marginTop || marginBottom || marginLeft || marginRight) { | |
var newLayoutParameters = view.LayoutParameters as ViewGroup.MarginLayoutParams; | |
newLayoutParameters.TopMargin = initialLayoutParameters.TopMargin + (marginTop ? insetTop : 0); | |
newLayoutParameters.BottomMargin = initialLayoutParameters.BottomMargin + (marginBottom ? insetBottom : 0); | |
newLayoutParameters.LeftMargin = initialLayoutParameters.LeftMargin + (marginLeft ? insetLeft : 0); | |
newLayoutParameters.RightMargin = initialLayoutParameters.RightMargin + (marginRight ? insetRight : 0); | |
view.LayoutParameters = newLayoutParameters; | |
} | |
} | |
return insetsCompat; | |
} | |
} | |
[Flags] | |
private enum WindowInsetsFlags { | |
None = 0, | |
PaddingLeft = 1 << 0, | |
PaddingRight = 1 << 1, | |
PaddingTop = 1 << 2, | |
PaddingBottom = 1 << 3, | |
MarginLeft = 1 << 4, | |
MarginRight = 1 << 5, | |
MarginTop = 1 << 6, | |
MarginBottom = 1 << 7 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment