Xamarin Forms Dark/Light 模式主题未应用于 Android 上的 shell 导航选项卡
Xamarin Forms Dark/Light Mode theme not applied to shell navigation tabs on Android
我有一个标准的 xamarin 表单项目(iOS 和 Android),使用 shell 进行导航。我已经使用合并词典实现了主题。这是我用来应用主题的方法:
public class MyShellRenderer : ShellRenderer
{
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(Xamarin.Forms.ShellItem shellItem)
{
return new MyShellBottomNavViewAppearanceTracker(this);
}
}
internal class MyShellBottomNavViewAppearanceTracker : IShellBottomNavViewAppearanceTracker
{
private MyShellRenderer myShellRenderer;
public MyShellBottomNavViewAppearanceTracker(MyShellRenderer myShellRenderer)
{
this.myShellRenderer = myShellRenderer;
}
Task SetAppTheme(PreferredTheme preferredTheme)
{
if (Application.Current is null)
return Task.CompletedTask;
BaseTheme defaultTheme;
if (Application.Current.RequestedTheme == OSAppTheme.Dark)
defaultTheme = new DarkTheme();
else
defaultTheme = new LightTheme();
return _mainThread.InvokeOnMainThreadAsync(() =>
{
BaseTheme theme = preferredTheme switch
{
PreferredTheme.Dark => new DarkTheme(),
PreferredTheme.Light => new LightTheme(),
PreferredTheme.Default => defaultTheme
};
CurrentTheme = theme;
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(theme);
}
OnPreferenceChanged(preferredTheme);
});
}
这适用于 iOS,但在 Android 上 ItemText 颜色没有改变。当深色模式主题的背景颜色与取消选择的选项卡的颜色相同(或接近)时,这是一个问题。图标按预期呈现。
我试过在 android 上实现自定义渲染,如下所示:
public void ResetAppearance(BottomNavigationView bottomView)
{
//Get and set background color from theme
Xamarin.Forms.Color xfcolor = (Xamarin.Forms.Color)App.Current.Resources["PageBackgroundColor"];
Android.Graphics.Color acolor = xfcolor.ToAndroid();
bottomView.SetBackgroundColor(acolor);
//Get and set state colors for menu items text
Xamarin.Forms.Color xfSelectedColor = (Xamarin.Forms.Color)App.Current.Resources["ColorBlue"];
Android.Graphics.Color aSelectedColor = xfSelectedColor.ToAndroid();
Xamarin.Forms.Color xfDeselectedColor = (Xamarin.Forms.Color)App.Current.Resources["ColorGray"];
Android.Graphics.Color aDeselectedColor = xfDeselectedColor.ToAndroid();
int[][] states = new int[][]
{
new int[] {-Android.Resource.Attribute.Checked }, // unchecked
new int[] { Android.Resource.Attribute.Checked } // pressed
};
int[] colors = new int[]
{
aSelectedColor,
aDeselectedColor
};
ColorStateList colorStateList = new ColorStateList(states, colors);
bottomView.ItemTextColor = colorStateList;
...
部分原因在于整个文本都应用了 aSelectedColor。
这是 SDK 中的错误还是我只是做错了什么?
找到解决方案(感谢 James Montemagno!!!)
找到灵感here
所以出于某些奇怪的原因,使用 mergedDictionaries 不适用于 Android。
相反,我根据 Hanselman.Forms 示例进行了以下重写:
Task SetAppTheme(PreferredTheme preferredTheme)
{
if (Application.Current is null)
return Task.CompletedTask;
BaseTheme defaultTheme;
if (Application.Current.RequestedTheme == OSAppTheme.Dark)
defaultTheme = new DarkTheme();
else
defaultTheme = new LightTheme();
return _mainThread.InvokeOnMainThreadAsync(() =>
{
BaseTheme theme = preferredTheme switch
{
PreferredTheme.Dark => new DarkTheme(),
PreferredTheme.Light => new LightTheme(),
PreferredTheme.Default => defaultTheme
};
CurrentTheme = theme;
//Previous code
/*ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(theme);
}*/
//New code
var applicationResourceDictionary = Application.Current.Resources;
ManuallyCopyThemes(theme, applicationResourceDictionary);
OnPreferenceChanged(preferredTheme);
});
}
void ManuallyCopyThemes(ResourceDictionary fromResource, ResourceDictionary toResource)
{
foreach (var item in fromResource.Keys)
{
if (toResource.ContainsKey(item))
toResource[item] = fromResource[item];
else
toResource.Add(item, fromResource[item]);
}
}
我有一个标准的 xamarin 表单项目(iOS 和 Android),使用 shell 进行导航。我已经使用合并词典实现了主题。这是我用来应用主题的方法:
public class MyShellRenderer : ShellRenderer
{
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(Xamarin.Forms.ShellItem shellItem)
{
return new MyShellBottomNavViewAppearanceTracker(this);
}
}
internal class MyShellBottomNavViewAppearanceTracker : IShellBottomNavViewAppearanceTracker
{
private MyShellRenderer myShellRenderer;
public MyShellBottomNavViewAppearanceTracker(MyShellRenderer myShellRenderer)
{
this.myShellRenderer = myShellRenderer;
}
Task SetAppTheme(PreferredTheme preferredTheme)
{
if (Application.Current is null)
return Task.CompletedTask;
BaseTheme defaultTheme;
if (Application.Current.RequestedTheme == OSAppTheme.Dark)
defaultTheme = new DarkTheme();
else
defaultTheme = new LightTheme();
return _mainThread.InvokeOnMainThreadAsync(() =>
{
BaseTheme theme = preferredTheme switch
{
PreferredTheme.Dark => new DarkTheme(),
PreferredTheme.Light => new LightTheme(),
PreferredTheme.Default => defaultTheme
};
CurrentTheme = theme;
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(theme);
}
OnPreferenceChanged(preferredTheme);
});
}
这适用于 iOS,但在 Android 上 ItemText 颜色没有改变。当深色模式主题的背景颜色与取消选择的选项卡的颜色相同(或接近)时,这是一个问题。图标按预期呈现。
我试过在 android 上实现自定义渲染,如下所示:
public void ResetAppearance(BottomNavigationView bottomView)
{
//Get and set background color from theme
Xamarin.Forms.Color xfcolor = (Xamarin.Forms.Color)App.Current.Resources["PageBackgroundColor"];
Android.Graphics.Color acolor = xfcolor.ToAndroid();
bottomView.SetBackgroundColor(acolor);
//Get and set state colors for menu items text
Xamarin.Forms.Color xfSelectedColor = (Xamarin.Forms.Color)App.Current.Resources["ColorBlue"];
Android.Graphics.Color aSelectedColor = xfSelectedColor.ToAndroid();
Xamarin.Forms.Color xfDeselectedColor = (Xamarin.Forms.Color)App.Current.Resources["ColorGray"];
Android.Graphics.Color aDeselectedColor = xfDeselectedColor.ToAndroid();
int[][] states = new int[][]
{
new int[] {-Android.Resource.Attribute.Checked }, // unchecked
new int[] { Android.Resource.Attribute.Checked } // pressed
};
int[] colors = new int[]
{
aSelectedColor,
aDeselectedColor
};
ColorStateList colorStateList = new ColorStateList(states, colors);
bottomView.ItemTextColor = colorStateList;
...
部分原因在于整个文本都应用了 aSelectedColor。
这是 SDK 中的错误还是我只是做错了什么?
找到解决方案(感谢 James Montemagno!!!)
找到灵感here
所以出于某些奇怪的原因,使用 mergedDictionaries 不适用于 Android。
相反,我根据 Hanselman.Forms 示例进行了以下重写:
Task SetAppTheme(PreferredTheme preferredTheme)
{
if (Application.Current is null)
return Task.CompletedTask;
BaseTheme defaultTheme;
if (Application.Current.RequestedTheme == OSAppTheme.Dark)
defaultTheme = new DarkTheme();
else
defaultTheme = new LightTheme();
return _mainThread.InvokeOnMainThreadAsync(() =>
{
BaseTheme theme = preferredTheme switch
{
PreferredTheme.Dark => new DarkTheme(),
PreferredTheme.Light => new LightTheme(),
PreferredTheme.Default => defaultTheme
};
CurrentTheme = theme;
//Previous code
/*ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(theme);
}*/
//New code
var applicationResourceDictionary = Application.Current.Resources;
ManuallyCopyThemes(theme, applicationResourceDictionary);
OnPreferenceChanged(preferredTheme);
});
}
void ManuallyCopyThemes(ResourceDictionary fromResource, ResourceDictionary toResource)
{
foreach (var item in fromResource.Keys)
{
if (toResource.ContainsKey(item))
toResource[item] = fromResource[item];
else
toResource.Add(item, fromResource[item]);
}
}