How do I get a reference to ActionBarDrawerToggle? - android

I have a Xamarin Forms application that I am porting from a FormsActivity to an AppCompatActivity. For functional requirements, the hamburger icon should always show, which I have done by using
NavigationPage.SetHasBackButton(nextPage, false);
But this does not work with AppCompat and the issue report has sat unaddressed for over a year, so I'm trying to get around the issue with a custom renderer. I can successfully create the icon and display it, but tapping on it does not display the correct behavior. I'm thinking what I need to do is set the DrawerIndicatorEnabled to true and call SyncState, but I need a reference to the ActionBarDrawerToggle to do that and I haven't figured out how to get it.
Edit: This is the bug report with screen shots:
https://github.com/xamarin/Xamarin.Forms/issues/2577
Here is the custom NavigationPageRenderer:
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))]
namespace HeaderTest.Droid
{
public class CustomNavigationPageRenderer : NavigationPageRenderer // APPCOMP
{
public CustomNavigationPageRenderer(Context context) : base(context)
{
}
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, false);
var context = (Activity)Context;
var toolbar = context.FindViewById<AToolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
var icon = new DrawerArrowDrawable(context)
{
SpinEnabled = false,
};
toolbar.NavigationIcon = icon;
}
return retVal;
}
}
}

Related

How to add clear button in CustomDatePicker control (.NET MAUI)?

I have started learning .NET MAUI technology. And I have noticed that DatePicker control does not have support for null/empty value.
So, I have created custom control using bindable property. Here is my code:
CustomDatePickerControl.cs
using System;
using System.Globalization;
​
namespace TestApp.Controls
{
public class CustomDatePicker : DatePicker
{
public string _format = null;
public static readonly BindableProperty CustomDateProperty =
BindableProperty.Create(nameof(CustomDate), typeof(DateTime?),
typeof(CustomDatePicker), DateTime.Now,
BindingMode.TwoWay, propertyChanged: OnDateChanged);
​
public DateTime? CustomDate
{
get { return (DateTime?)GetValue(CustomDateProperty); }
set { SetValue(CustomDateProperty, value); }
}
​
static void OnDateChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (CustomDatePicker)bindable;
var dateFormate = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
if (control.CustomDate.HasValue)
{
if (control._format != null)
{
control.Format = control._format;
}
else
{
control.Format = dateFormate;
}
control.Date = control.CustomDate.Value;
control.Opacity = 1;
}
else
{
control._format = dateFormate;
​
//Added character in quotes to escape it, otherwise it will not get display properly.
control.Format = string.Format("Selec't' 'Date'");
control.Opacity = 0.3;
}
}
​
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
​
if (propertyName == "Date")
{
CustomDate = Date;
}
}
}
}
Use in MainPage.xaml page
<control:CustomDatePicker x:Name="datePicker" />
MainPage.xaml.cs
{
InitializeComponent();
datePicker.CustomDate = null;
}
It does work fine in both Android and iOS. Now, I want to add clear action button to my CustomDatePicker control so that if user want to clear selected date they can.
Does anyone know how I can achieve it in MAUI? I do not know much about Xamarin.Forms or MAUI as I'm new to it. If someone can help me on this it will be really helpful.
Expected Output:

SwiftUI ObservableObject + #Published equivalent in flutter

I developed an iOS app in SwiftUI, and now need to port it to Android, and decided to try Flutter. After overcoming super verbose and/or ugly nested widgets, I got stuck on state management. In SwiftUI:
class MySharedObj : ObservableObject {
#Published var someVar = 0
}
Now I can simply drop "#ObservedObject var obj:MySharedObj" in ANY views, and whenever the someVar is changed anywhere, all views "observing" this object are updated automatically. Is there something equivalent in Flutter? Currently I manage a list of "listeners" manually as follows:
class ObservableObject {
List<State> _listeners = [];
ObservableObject subscribe(State state) { _listeners.add(state); return(this); }
ObservableObject unsubscribe(State state) { _listeners.remove(state); return(this); }
ObservableObject notify() { _listeners.forEach((l) => l.setState((){})); return(this); }
}
class MySharedObj : ObservableObject {
int _someVar = 0;
int get someVar => _someVar;
void set someVar(int v) { _someVar = v; notify(); }
}
class SomeView1State extends State<SomeView1> {
#override initState(){widget.obj.subscribe(this);super.initState();}
#override dispose(){widget.obj.unsubscribe(this);super.dispose();}
}
...
This sort of works, but it's ugly and again verbose (it seems to be Android's theme).
I think you want to look at the provider package. There's a great discussion of it here.

how to do picker to use only one line to show the selected value?

I am working with xamarin.forms and I am using a picker.
But, depend of the selected value, on android it breaks the line...But I need it always use only one line. How can I do that?
You can create a custom renderer for the Picker as the comment suggested, and then in your renderer, you can for example code like this:
[assembly: ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace NameSpace.Droid
{
public class MyPickerRenderer : PickerRenderer
{
private bool isShown;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var et = this.Control as EditText;
et.SetSingleLine(true);
}
}
}
}

How to set page icon in Xamarin Forms?

I'm trying to set page icon. There is App class of PCL below.
public App()
{
CustomMainPage mainPage = new CustomMainPage();
NavigationPage rootPage = new NavigationPage(mainPage);
this.MainPage = rootPage;
}
What I tried to do?
NavigationPage.SetTitleIcon(mainPage, "icon.png");
The second approach.
NavigationPage.SetTitleIcon(this, "icon.png");
The third approach.
NavigationPage.SetTitleIcon(rootPage, "icon.png");
File icon.png is situated into Resources/drawable.
And finally I decided to implement my custom renderer for the NavigationPage in Xamarin Forms. NavigationPage is setted to MainPage property into App class of PCL.
I created DroidNavigationRenderer class into Android project.
[assembly: ExportRenderer(typeof(NavigationPage), typeof(DroidNavigationPageRenderer))]
namespace App1.Droid.DroidRenderers
{
public class DroidNavigationPageRenderer : NavigationPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
var actionBar = ((Activity)Context).ActionBar;
actionBar.SetIcon(Resource.Drawable.icon);
}
}
}
But actionBar is always returns as null.
What I do wrong and how to fix it?
In your ContentPage, you have the Icon property.
You can set it this way
Icon = Device.OnPlatform("Menu", "ic_fa_bars.png", "Assets/Icons/reload.png");
What is your CustomMainPage class? If I have TabbedPage and set one of its child I do it this way:
var navigationPage = new NavigationPage(mainPage);
if (Device.RuntimePlatform == Device.iOS)
{
navigationPage.Icon = "services.png";
}
hope it helps

Add Mapbox to Android View in Xamarin Forms Custom Renderer

I cannot figure out how to get a Mapbox map going in a custom view renderer on Android using Xamarin.Forms. It's driving me bonkers.
In my PCL, I have a map view.
public class MapView: View
{
public MapView() { }
}
For iOS, the "getting started" help was close enough to get it working on iOS, like so:
[assembly: ExportRenderer (typeof(Shared.Mobile.MapView), typeof(MapViewRenderer))]
namespace Clients.iOS
{
public class MapViewRenderer : ViewRenderer<Shared.Mobile.MapView, UIView>
{
protected override void OnElementChanged(ElementChangedEventArgs<Shared.Mobile.MapView> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
var uiView = new UIView(new CoreGraphics.CGRect(0, 0, 500, 700));
SetNativeControl(uiView);
var mapView = new MapView(Control.Bounds);
mapView.SetCenterCoordinate(new CoreLocation.CLLocationCoordinate2D(40.81, -96.68), false);
mapView.SetZoomLevel(11, false);
mapView.AddAnnotation(new PointAnnotation
{
Coordinate = new CoreLocation.CLLocationCoordinate2D(40.81, -96.68),
Title = "Lincoln, NE",
Subtitle = "What-what"
});
uiView.AddSubview(mapView);
}
}
}
On the Android side, not so much. (https://components.xamarin.com/gettingstarted/mapboxsdk). They're putting in XML and an Activity of sorts, but my knowledge in mobile doesn't extend far from Xamarin.Forms at the moment, so I can't seem to bridge the gap between the two. My Android renderer looks like this:
public class MapViewRenderer : ViewRenderer<Shared.Mobile.MapView, Android.Views.View>
{
protected override void OnElementChanged(ElementChangedEventArgs<Shared.Mobile.MapView> e)
{
base.OnElementChanged(e);
var view = new Android.Views.View(Context);
SetNativeControl(view); // NullReferenceException will be thrown if the native control is not set
if (Control == null)
{
return;
}
var mapView = new MapView(Forms.Context, "thisismyaccesscode");
mapView.CenterCoordinate = new LatLng(41.885, -87.679);
mapView.ZoomLevel = 11;
mapView.SetMinimumHeight(250);
mapView.SetMinimumWidth(250);
mapView.AddMarker(new MarkerOptions().SetPosition(new LatLng(40.81, -96.68)).SetTitle("Lincoln, NE"));
view.AddSubview(mapView) // I wish this method existed
}
}
My final call to AddSubview(mapView) is not in fact a method of the View class as it is the UIView class on iOS. Here's where I'm stuck. I cannot figure out how to display the MapView. Please help.
As you have already mentioned you can't call AddSubview as it is an iOS method.
On Android its the equivalent of AddView.
However - You are attempting to do this type of operation on a Android View object and not on a ViewGroup object, so its not possible.
First instead of doing:-
var view = new Android.Views.View(Context);
try instantiating the MapView directly such like:-
var view = new MapView(Context, "thisismyaccesscode");
Your SetNativeControl call on the view is fine.
I haven't tried the Mapbox component, so I'm unclear on the exact parameter types it is expecting in the code above.
Should that not work, however, then do something like the following:-
var view = new Android.Widget.FrameLayout(Context);
var mapView = new MapView(Forms.Context, "thisismyaccesscode");
mapView.CenterCoordinate = new LatLng(41.885, -87.679);
mapView.ZoomLevel = 11;
mapView.SetMinimumHeight(250);
mapView.SetMinimumWidth(250);
mapView.AddMarker(new MarkerOptions().SetPosition(new LatLng(40.81, -96.68)).SetTitle("Lincoln, NE"));
view.AddView(mapView);
SetNativeControl(view);
You will have to change your first line to the following also:-
public class MapViewRenderer : ViewRenderer<Shared.Mobile.MapView, Android.Widget.FrameLayout>

Categories

Resources