CustomPicker Ok and Cancel buttons' color - xamarin.forms

I have this custompicker class in android project:
public class CustomPickerRenderer : PickerRenderer
{
private Context context;
private IElementController ElementController => Element as IElementController;
private AlertDialog _dialog;
public CustomPickerRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control == null || e.NewElement == null) return;
Control.Click += Control_Click1;
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click1;
base.Dispose(disposing);
}
private void Control_Click1(object sender, EventArgs e)
{
Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
//change the text or color here
builder.SetNegativeButton(Html.FromHtml("<font color='#039BE5'>Cancel</font>"), (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
//change the text or color here
builder.SetPositiveButton(Html.FromHtml("<font color='#039BE5'>OK</font>"), (s, a) =>
{
ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
I tried running my project on my phone Xiaomi POCOPHONE F1 (Android 9) and 2 emulators (Android 8.1) and the colors of cancel and ok buttons are designed Perfectly. But when I tried running the project on Huawei PLE-701L and SAMSUNG SM-T365 (Android 5.1) the color of the buttons didn't changed.
Any suggestions?

Get the button object through the API of dialog and set the text color of the button. This method can be personalized. One point needs to be noted: it must be called after show
in your custom renderer,below _dialog.Show();
....
_dialog.Show();
Button btnOk = _dialog.GetButton((int)DialogInterface.ButtonPositive);
btnOk .SetTextColor(Color.Red);
Button btnCancel= _dialog.GetButton((int)DialogInterface.ButtonNegative);
btnCancel.SetTextColor(Color.Red);

add this style in style.xml
<style name="SpinnerDialog" parent="Theme.AppCompat.Light.Dialog">
<item name="android:popupBackground">#ff00ff</item>
<item name="colorPrimary">#ff00ff</item>
<item name="colorPrimaryDark">#ffff00</item>
<item name="colorAccent">#ff0000</item>
</style>
you can change allthe color including buttons.
and you can also use
<style name="AlertDialogCustom" parent="android:Theme.Material.Light.Dialog.Alert">
<item name="android:colorPrimary">#1e87f0</item>
<item name="android:colorAccent">#1e87f0</item>
</style>
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#1e87f0</item>
</style>

The Question is answered here: Picker button's color not changing on android 5.1
I added the styles code in the correct answer in the link, and it worked!

Related

custom LabelRenderer shows wrong text style inside list view on scroll on Xamarin iOS

I am working on an App that requires one list view having text labels with NSUnderlineStyle on user deletion.
As per the requirement user have Delete/restore option in detail screen. On delete confirmation the text label should be underline style for that particular cell.
I am using LabelRenderer for NSUnderlineStyle in Xamarin iOS.
But currently ListView displays text Labels with underline style which is not deleted by user on list view scroll. The underline style are swapping from one cell label to another on list view scroll.
Below my sample code.
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Control == null)
{
return;
}
if (this.Element is ExtendedLabel extended)
{
var strikethroughStyle = extended.IsStrikeThrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None;
this.Control.AttributedText = new NSMutableAttributedString(
extended.Text ?? string.Empty,
this.Control.Font,
strikethroughStyle: strikethroughStyle);
}
}
This is the common issue of TableView Cell Resue , tableView will reuse the cell for the visible(inside screen shot) ones , so it would show the previous style .
To solve this we can forcedly set the style each time when the cell is going to display .
Create custom renderer for ListView , and do this in WillDisplay method ,before it we need to override TableView's Delegate.
[assembly: ExportRenderer(typeof(ListView), typeof(MyRenderer))]
namespace FormsApp.iOS
{
public class MyDelegate : UITableViewDelegate
{
List<Model> data;
public MyDelegate(List<Model> _data)
{
data = _data;
}
public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
var views = cell.ContentView.Subviews;
foreach (var view in views)
{
if(view is LabelRenderer renderer)
{
UILabel label = renderer.Control;
var strikethroughStyle = data[indexPath.Row].YourProperty?NSUnderlineStyle.Single : NSUnderlineStyle.None;
label.AttributedText = new NSMutableAttributedString(
label.Text ?? string.Empty,
label.Font,
strikethroughStyle: strikethroughStyle);
}
}
}
}
public class MyRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
IEnumerable<Model> data = (IEnumerable<Model>)Element.ItemsSource;
Control.Delegate = new MyDelegate(data.ToList());
}
}
}
}

Set DarkMode on the first page status bar xamarin forms android

Using xamarin forms and we are adding ability to switch between Dark-Light mode. All is good however the first page of the app in android whatever I do the status bar color wont change.
I guess that in the android project I have to call SetTheme(...) before OnCreate.
Or Am I missing something here?
Question
How do you set the status bar color depending on theme? code below does not change once the android has loaded
public void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
window?.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window?.ClearFlags(WindowManagerFlags.TranslucentStatus);
window?.SetStatusBarColor(color.ToPlatformColor());
var flag = (StatusBarVisibility)SystemUiFlags.LightStatusBar;
if (window != null)
{
window.DecorView.SystemUiVisibility = darkStatusBarTint ? flag : 0;
}
}
Suggestions?
thanks
Try this:
private void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
if (window != null)
{
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.SetStatusBarColor(color.ToPlatformColor());
StatusBarVisibility flags = default;
if (darkStatusBarTint)
flags |= (StatusBarVisibility)SystemUiFlags.LightStatusBar;
else
flags &= ~(StatusBarVisibility)SystemUiFlags.LightStatusBar;
window.DecorView.SystemUiVisibility = flags;
}
}
Or
private void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
if (window != null)
{
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.SetStatusBarColor(color.ToPlatformColor());
window.DecorView.SystemUiVisibility = darkStatusBarTint
? (StatusBarVisibility)SystemUiFlags.LightStatusBar
: StatusBarVisibility.Visible;
}
}
Both functions work.
You can update the StatusBar color in the MainActivity.OnCreate method and also listen to the App.Current.RequestedThemeChanged event.
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
ApplyStatusBarColor(App.Current.RequestedTheme);
App.Current.RequestedThemeChanged += (s, e) => ApplyStatusBarColor(e.RequestedTheme);
}
private void ApplyStatusBarColor(Xamarin.Forms.OSAppTheme osAppTheme)
{
if (osAppTheme == Xamarin.Forms.OSAppTheme.Dark)
SetStatusBarColor(Xamarin.Forms.Color.Blue, false);
else
SetStatusBarColor(Xamarin.Forms.Color.Yellow, true);
}
}

iOS 14 DatePicker renderer

I am having some difficulty figuring out how to properly update my existing custom renderer I have for my DatePicker on iOS to display the DatePicker with a different preferred style as is mentioned in this article here (albeit it is for swift) https://medium.com/better-programming/introducing-swifts-new-modern-date-picker-37bb5e0a106
My renderer is as follows:
public class BorderlessDatePickerRenderer : DatePickerRenderer
{
public override void LayoutSubviews()
{
base.LayoutSubviews();
var element = Element as BorderlessDatePicker;
Control.BorderStyle = UITextBorderStyle.None;
if (element.Date.Year == 1900) {
Control.Text = "";
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var element = Element as BorderlessDatePicker;
if (Control != null && element.Date.Year == 1900) {
Control.Text = "";
}
}
The BorderlessDatePicker itself is just an empty class that extends the DatePicker Xamarin.Forms control. The root of my woes is that I am not sure how to properly set a PreferredDatePickerStyle on my Control object given that Control is a UITextField under the hood instead of a UIDatePicker. In essence what I would like to do is instead of displaying the Date picker using the compact style that seems to be default for iOS 14, I would like for it to be displayed as wheels instead by being to do something like:
PreferredDatePickerStyle = UIDatePickerStyle.Wheels;
After some more researching, and browsing the xamarin github, I've come across this solution:
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if(e.NewElement != null && this.Control != null)
{
try
{
if (UIDevice.CurrentDevice.CheckSystemVersion(14, 0))
{
UIDatePicker picker = (UIDatePicker)Control.InputView;
picker.PreferredDatePickerStyle = UIDatePickerStyle.Wheels;
}
} catch (Exception ex)
{
Log.Error(ex, "Failed to set PreferredDatePickerStyle to be UIDatePickerStyle.Wheels for iOS 14.0+");
}
}
}

Is it possible to use AppThemeBinding in Android Custom Styles?

I'm trying to implement Darkmode for Android by using the new AppThemeBinding. It works fine for Android and iOS but i do not have a clue on how to implement it for custom renderers or custom styles.
For example i got a custom Stepper renderer which looks something like this:
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Android.Widget.Button buttonDown = (Android.Widget.Button)Control.GetChildAt(0);
Android.Widget.Button buttonUp = (Android.Widget.Button)Control.GetChildAt(1);
if(e.NewElement != null)
{
//Button Down
buttonDown.SetBackgroundResource(Resource.Drawable.button_bg_left);
buttonDown.LayoutParameters = new LinearLayout.LayoutParams(DpToPixel(50), DpToPixel(33));
buttonDown.SetPadding(0,0,0,0);
buttonDown.SetTextColor(Android.Graphics.Color.ParseColor("#007bff"));
//Button Up
buttonUp.SetBackgroundResource(Resource.Drawable.button_bg_right);
buttonUp.LayoutParameters = new LinearLayout.LayoutParams(DpToPixel(50), DpToPixel(33));
buttonUp.SetPadding(0, 0, 0, 0);
buttonUp.SetTextColor(Android.Graphics.Color.ParseColor("#007bff"));
}
}
}
I'm setting a background resource which is a .xml file and looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="1dp" android:color="#007bff" />
<corners
android:topLeftRadius="5dp"
android:bottomLeftRadius="5dp"/>
</shape>
Since the AppThemeBinding is a Markup Extension and works inside .xaml files, i have no clue how i could implement color changes for my android specific renderers?
How could i go about changing the color of my custom shape for Light/Darkmode?
You can Detect the current system theme in the renderer and then set the corresponding color:
class MyStepperRenderer : StepperRenderer
{
public MyStepperRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
OSAppTheme currentTheme = Xamarin.Forms.Application.Current.RequestedTheme;
if (currentTheme == OSAppTheme.Light)
{
//
}
else
{
//
}
}
}

Styling the list view of Picker class

I am sorry to be asking what seems really obvious question but I've been unable to set the properties (e.g. background color) of the list view / contents when using the picker
The Picker properties style what you see before you expand the list to select contents, but I cannot see or find how to affect the latter
In this example from my XAML the collapsed view of the Picker is styled correctly, but when it opens the background is white / transparent
Sorry, I have looked in many links and just can't find the info
<Picker
VerticalOptions="CenterAndExpand"
Grid.Column="1"
Grid.Row="1"
Title="PICKER"
BackgroundColor="Transparent"
TitleColor="White"
FontSize="Medium"
Style="{StaticResource AlphabetPicker}"
x:Name="AlphabetPicker"
ItemsSource="{Binding Alphabet}"
SelectedIndexChanged="GetLetterSelected"
HorizontalOptions="Start">
You could use custom renderer.
I follow the code in the link: Customize the Xamarin.Forms Picker Popup List
MyPicker.cs
public class MyPicker : Xamarin.Forms.Picker
{
}
MyPickerRenderer.cs
[assembly: ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace XamarinDemo.Droid.Renderer
{
class MyPickerRenderer : PickerRenderer
{
IElementController ElementController => Element as IElementController;
public MyPickerRenderer(Context context) : base(context)
{
}
private AlertDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null || e.OldElement != null)
return;
Control.Click += Control_Click;
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click;
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Xamarin.Forms.Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
// set style here
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetBackgroundColor(Android.Graphics.Color.Yellow);
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetNegativeButton("Cancel ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Ok ", (s, a) =>
{
ElementController.SetValueFromRenderer(Xamarin.Forms.Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
}
Xaml:
<StackLayout>
<local:MyPicker x:Name="picker"
Title="Select a monkey"
TitleColor="Red">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</Picker.ItemsSource>
</local:MyPicker>
</StackLayout>

Resources