Can't add ToolbarItem to ContentPage - android

I declare my main page:
public App () {
MainPage = new NavigationPage(new MainPage());
}
Then on main page open ContantPage after tapping a button:
class MainPage : ContentPage {
public MainPage() {
button.Clicked += to_my_contentpage;
//...
}
private async void to_my_contentpage(object sender, EventArgs e) {
await Navigation.PushModalAsync(new my_contentpage());
//using PushAsync doesn't help
}
}
And try to show button on this page as ToolbarItem:
public class my_contentpage : ContentPage {
public my_contentpage () {
ToolbarItem AddButton = new ToolbarItem("AddButton", "AddIcon.png", () => {
Console.WriteLine("Clicked");
});
this.ToolbarItems.Add(new ToolbarItem());
//...
this.Content = new StackLayout { Children = { header, listView } };
}
}
I feel like doing everithing according to this answer but my ToolbarItem is not included to my page:
How do i add toolbar for android in xamarin,forms as ToolbarItem is not working for .droid?
What am I doing wrong?

PushModalAsync is not going to work in this case, since you need to have a Navigation Bar in order to add ToolBarItems to it.
Since a Modal page explicitly does not show/contain a NavigationBar you are not going to be able to do it this way.
Solutions:
Create a Custom NavigationBar and add any Views you need to it.
Do not use a Modal Page.
Hope this helps.

Related

How to set cursor colour of entry on MAUI for Android

I can't find how to change the cursor colour of an entry field on MAUI for Android.
I'm writing an app supporting dark theme and I don't want the entry box to have a light background. Unfortunately, the default cursor colour is dark purple, which has insufficient contrast and makes it very hard to see.
I'd be happy if it were the same colour as the text or if I could set it independently.
Any suggestions?
You can add the code below to app.xaml.cs file, and the TextCursorDrawable can not be used on the device which Android API version is below 29.
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
{
#if ANDROID
handler.PlatformView.TextCursorDrawable.SetTint(Colors.Red.ToPlatform());
#elif IOS || MACCATALYST
#elif WINDOWS
#endif
});
}
}
I don't think there is a easy way to add cursor color to MAUI styles.
To change entry cursor color You could use EntryHandler and write in it android native code.
app.xaml.cs:
public partial class App : Application
{
public App()
{
InitializeComponent();
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("CursorColor", (handler, view) =>
{
#if __ANDROID__
handler.PlatformView.TextCursorDrawable.SetTint(Colors.Green.ToAndroid());
#endif
});
MainPage = new AppShell();
}
}
Other solution would be to create custom Entry:
CursorEntry.cs:
public class CursorEntry : Entry
{
public static BindableProperty CursorColorProperty = BindableProperty.Create(
nameof(CursorColor), typeof(Color), typeof(CursorEntry), Colors.Black);
public Color CursorColor
{
get => (Color)GetValue(CursorColorProperty);
set => SetValue(CursorColorProperty, value);
}
public CursorEntry()
{
}
}
CursorEntryHandler.cs:
namespace mauicursor
{
#if ANDROID
public sealed partial class CursorEntryHandler : EntryHandler
{
public CursorEntryHandler()
{
Mapper.AppendToMapping("CursorEntryCustomization", MapCursorEntry);
}
private void MapCursorEntry(IEntryHandler entryHandler, IEntry entry)
{
if (entry is CursorEntry cursorEntry && entryHandler is CursorEntryHandler cursorEntryHandler)
{
SetCursorColor(cursorEntry);
}
}
}
#else
public partial class CursorEntryHandler : EntryHandler
{
}
#endif
}
in Platforms Android create CursorEntryHandler.android.cs:
namespace mauicursor
{
public partial class CursorEntryHandler
{
AppCompatEditText _nativeEntry;
protected override AppCompatEditText CreatePlatformView()
{
_nativeEntry = new AppCompatEditText(Context);
return _nativeEntry;
}
internal void SetCursorColor(CursorEntry entry)
{
_nativeEntry.TextCursorDrawable.SetTint(entry.CursorColor.ToAndroid());
}
}
}
add handler in MauiProgram.cs
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(CursorEntry), typeof(CursorEntryHandler));
});
use in any view:
xmlns:views="clr-namespace:mauicursor"
<views:CursorEntry
Text="Cursor color"
FontSize="18"
Placeholder="Green"
HorizontalOptions="Center"
CursorColor="Yellow"/>
But to use dark and light mode you would probably have to programaticaly detect if it is dark or light mode and recreate views. Maybe there are better ways for this part like somehow setting themes.

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 do I get a reference to ActionBarDrawerToggle?

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;
}
}
}

page has two tool bars

I am starting the NavigationPage in the App.cs class:
MainPage = new NavigationPage(new PageA());
In PageA(), I am are calling "PushAsync":
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void btnCourseList_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new PageB());
}
}
If I click back button on PageB(), it goes to PageA() in which it has two tool bars.
Any idea how to fix this?
The reason for it is very simple you are providing two navigation pages in the page lifecycle which is in turn showing two Navbar's
Solution :
In your App.xaml.cs add a static NavigationPage property something like this:
public static NavigationPage NavigationPage { get; set; }
Assign this a Page in your app.xaml constructor something like this :
App.NavigationPage = new NavigationPage(new yourPage) ;
Then Assign this NavigationPage as your MainPage like this:
MainPage=App.NavigationPage;
Now Whenever you plan on going to the next page call the next page like this:
App.NavigationPage.PushAsync(new YourNewPage());
Goodluck!
In case of queries revert.

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

Categories

Resources