My scenario is, I have a Tabbed page in Xamarin Forms:
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var playPage = new NavigationPage(new PlayPage())
{
Title = "Play",
Icon = "play.png"
};
var settingsPage = new NavigationPage(new SettingsPage())
{
Title = "Settings",
Icon = "settings.png"
};
var favoritesPage = new NavigationPage(new FavoritesPage())
{
Title = "Favorites",
Icon = "fave.png"
};
var aboutPage = new NavigationPage(new AboutPage())
{
Title = "About",
Icon = "info.png"
};
Children.Add(playPage);
Children.Add(favoritesPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
}
I want to add a pause and play function to my app. On start up, the PlayPage would initially have the play.png icon and when I click on the PlayPage again it would change the icon to pause.png. Page is not changing just the page icon. Anyone has any idea how this could be done?
Edit:
So I have created a custom renderer, in OnElementChanged I utilize the ViewControllerSelected:
var tabbarController = (UITabBarController)this.ViewController;
if (null != tabbarController)
{
tabbarController.ViewControllerSelected += OnTabBarReselected;
}
And my OnTabBarReselected I have:
private void OnTabBarReselected(object sender, UITabBarSelectionEventArgs e)
{
switch (TabBar.SelectedItem.Title)
{
case "Play":
TabBar.SelectedItem.Title = "Pause";
TabBar.SelectedItem.Image = UIImage.FromFile("pause.png");
break;
}
}
This only does half of the work. It changes the Title of the selected tab bar from Play to Pause after I click on the same tab but not the Icon. The icon remains "play.png" until I get out of that tab page (selecting another tab). Anyone has any idea why?
You will need to implement a custom renderer to pull this off. There are some implementations on James Montemagno's blog where he talks about changing the icons.
iOS:
http://motzcod.es/post/138225183932/tintcolor-selectedimage-xamarin-forms-ios
Droid:
http://motzcod.es/post/157544468267/xamarin-forms-android-selected-and-unselected-tab-colors
This is however not necessarily related to your requirement of tapping the icon and changing that specific icon since all this code only runs when the page initially loads. It could be a nice starting point though. Check in there if there's a property on TabbedPage that changes when you tap on the current tab and change the icon at that point.
You also have a OnCurrentPageChanged event you can override in TabbedPage, but that isn't called when the page is already active.
Related
I used the following code in MainPage.xaml.cs to add acrylic effect on the TitleBar
public void AcrylicTitleBar()
{
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
var title = ApplicationView.GetForCurrentView();
title.TitleBar.ButtonBackgroundColor = Colors.Transparent;
title.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
title.TitleBar.ButtonForegroundColor = (Color)Resources["SystemBaseHighColor"];
}
but I don't know why the TitleBar title is gone.
If I remove the above code the TitleBar title comes back. can someone please help me?
Your code is not applying any "Acrylic" effect to your app Title bar .
It is simply setting the button background color to "Transparent" which is no where close to the acrylic.
In order to have an acrylic title bar you need to do the following :
In your MainPage.xaml.cs , add code for hiding the default title bar and update its layout so that it still works like the default toolbar :
public MainPage()
{
// Hide default title bar.
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
UpdateTitleBarLayout(coreTitleBar);
}
private void UpdateTitleBarLayout(CoreApplicationViewTitleBar coreTitleBar)
{
// Get the size of the caption controls area and back button
// (returned in logical pixels), and move your content around as necessary.
LeftPaddingColumn.Width = new GridLength(coreTitleBar.SystemOverlayLeftInset);
RightPaddingColumn.Width = new GridLength(coreTitleBar.SystemOverlayRightInset);
TitleBarButton.Margin = new Thickness(0, 0, coreTitleBar.SystemOverlayRightInset, 0);
// Update title bar control size as needed to account for system size changes.
AppTitleBar.Height = coreTitleBar.Height;
}
private void CoreTitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
UpdateTitleBarLayout(sender);
}
Next , in your MainPage.xaml add AcrylicBrush as the main or parent grid background (Note : that this grid should wrap all the contents in the page ):
<Grid>
<Grid.Background>
<AcrylicBrush BackgroundSource="HostBackdrop"
TintColor="{ThemeResource SystemAltHighColor}"
FallbackColor="{ThemeResource SystemAltHighColor}"
TintOpacity="0.5">
</AcrylicBrush>
</Grid.Background>
</Grid>
Hope this helps!
I just started with Xamarin forms and followed this example. But for the landscape mode it always has Navigation drawer opened. Is this default behavior? Below is my code
public class NavigationDrawer : MasterDetailPage // Navigation Drawer using MasterDetailPage
{
public override bool ShouldShowToolbarButton()
{
return true;
}
ContentPage gotoPage;
public NavigationDrawer()
{
Title = "Navigation Drawer Using MasterDetailPage";
string[] myPageNames = { "Camera2 Demo", "Second", "Third" };
SizeChanged += NavigationDrawer_SizeChanged;
ListView listView = new ListView
{
ItemsSource = myPageNames,
};
this.Master = new ContentPage
{
Title = "Options",
Content = listView,
Icon = "hamburger.png"
};
listView.ItemTapped += (sender, e) =>
{
switch (e.Item.ToString())
{
case "Camera2 Demo":
gotoPage = new CameraPage();
break;
case "Second":
gotoPage = new SecondPage();
break;
case "Third":
gotoPage = new ThirdPage();
break;
default:
gotoPage = new NavigationPage1();
break;
}
Detail = new NavigationPage(gotoPage);
((ListView)sender).SelectedItem = null;
this.IsPresented = true;
};
Detail = new NavigationPage(new HomePage());
IsPresented = false;
//// For Windows Phone, provide a way to get back to the master page.
//if (Device.OS == TargetPlatform.WinPhone)
//{
// (this.Detail as ContentPage).Content.GestureRecognizers.Add(
// new TapGestureRecognizer((view) =>
// {
// this.IsPresented = true;
// }));
//}
}
Question
1) How would I control opening and closing of Navigation Drawer? I found a way where it would give us control over the width of the navigation Drawer. Here is the Link. But is this the best option available right now?
1) Since project requires to be crossplaform Xamarin forms controls seems to be one of the option.
2) Should we go with Custom controls and not Xamarin forms controls?
I just started with Xamarin sample code would appreciate if someone can guide me through this.
1) How would I control opening and closing of Navigation Drawer?
Use this.IsPresented = true; to open and this.IsPresented = false; to close the drawer.
About the other questions I don't understand you good, but depending on your requirements, you should create custom controls or download one from NuGet.
Note:
I believe the most important thing for a beginner is to learn how to implement a native code using DependencyService and also to use Design patterns like MVVM.
You would need to set MasterBehavior = MasterBehavior.Popover on the MasterDetailPage to force it to exhibit the behaviour you are after, otherwise it will default to MasterBehavior.Default, which in Landscape mode will be always open.
i have been creating a cefsharp browser in C#. i have made it so you can have multiple tabs and it loads the pages correctly. however, i cannot seem to find how i can rename the tab to the name of the page.
this is the code in the load event for form1.cs:
Cef.Initialize();
toolTip1.SetToolTip(button1, "Settings");
TabPage tab = new TabPage();
Tab newtab = new Tab();
newtab.Show();
newtab.TopLevel = false;
newtab.Dock = DockStyle.Fill;
tab.Controls.Add(newtab);
tabControl1.TabPages.Add(tab);
i have tried:
private void myBrowser_isLoading(object sender)
{
myBrowser.Parent.Parent.Text = myBrowser.Title;
}
but that doesn't work.
then this is the code for tab.cs:
public Tab()
{
InitializeComponent();
// Start the browser after initialize global component
InitializeChromium();
}
public CefSharp.WinForms.ChromiumWebBrowser myBrowser;
public bool nav = new bool();
public void InitializeChromium()
{
myBrowser = new CefSharp.WinForms.ChromiumWebBrowser("http://www.google.com");
this.Controls.Add(myBrowser);
myBrowser.Dock = DockStyle.Fill;
myBrowser.Parent = panel2;
if (nav == true)
{
myBrowser.Load(textBox1.Text);
nav = false;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Cef.Shutdown();
}
again, i am using c# with the latest build of cef sharp(or atleast the one installed from the nuget package manager).
In your tab function in form1.cs, you need to add a title changed function like this
browser.TitleChanged += OnBrowserTitleChanged;
you also need to specify what browser is and set dockstyle to fill like this
ChromiumWebBrowser browser = new ChromiumWebBrowser("google.com");
tab.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
now for the OnBrowserTitleChanged, you will need an EventArg which will tell the tab to have the document title in this format
this.InvokeOnUiThreadIfRequired(() => browserTabControl.SelectedTab.Text = args.Title);
this will add the document title to the tabcontrol browserTabControl is the name of the tabcontrol you will have to change browserTabControl to whatever name you have for the tabcontrol. Also the code you have does not belong with cef initialize. you need to create an addNewTab method with all the functions that will be processed when you want to add a new tab. Also, you cannot use a panel if you want to have tabs. you need a tabcontrol
I have app where in I have master details page something like this:
I would have this(left menu bar settings, login) static for all the pages. Since I am using master details page I am using messagingcenter to navigate between pages as given here:
MessagingCenter.Send(new RedirectClass.OpenDetails(), RedirectClass.OpenDetails.Key);
But now since I have used master details I cannot navigate back using back button. The back button would exit the application. Say user is at 'page A', When user clicks on settings menu the user should be redirected to settings page(settings page will all have left menu), so on click of back button on settings page should redirect user to 'Page A'. Which is not happening. ANy help?
MessagingCenter.Subscribe<RedirectClass.OpenDetails>(this, RedirectClass.OpenDetails.Key, (sender) =>
{
Detail = new NavigationPage(new Details())
{
BarBackgroundColor = Color.FromRgb(172, 183, 193),
BarTextColor = Color.Black,
BackgroundColor = Color.White
};
});
Instead of overriding the Detail page in your MessagingCenter callback
Detail = new NavigationPage(new Details())
You should use the Detail page's Navigation property to push the new page on the top of the stack
Detail.Navigation.PushAsync(new Details())
make sure your initial detail page is wrapped in a navigationpage
I was having same issue, Detail.Navigation.PushAsync(itemSelected) makes hamburger menu vanish I decided to use my own stack datatype for Master detail page. It was bit tricky to keep track and code but working fine.
Initialize it at the app load with current Detail page and for each item selected Push new page on top of stack.
public partial class MyMasterDetailPage: MasterDetailPage
{
private Stack navigationStack = new Stack();
public MyMasterDetailPage()
{
InitializeComponent();
navigationStack.Push(Detail);
try
{
masterPage.listView.ItemSelected += OnItemSelected;
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.Message);
}
}
Override OnBackButtonPressed() in same Page code behind
protected override bool OnBackButtonPressed()
{
try
{
var lastPage = navigationStack.Pop();
if (lastPage.Equals(Detail))
lastPage = navigationStack.Pop();
Detail = (Page)lastPage;
IsPresented = false;
// to avoid app close when complete pop and new page is push on top of it
if (navigationStack.Count == 0)
navigationStack.Push(Detail);
return true;
}
catch (Exception)
{
return base.OnBackButtonPressed();
}
}
I am attempting to create an application in MonoMac/Xamarin.Mac that does not have a dock icon, nor a visible window when it launches and only an icon in the top-right menu bar.
I have set LSUIElement = 1 (tried both String and Boolean types) in Info.plist, but the status menu icon isn't displayed at all when the application launches. The only way I can get it to appear is by removing the LSUIElement flag, although then the dock icon becomes visible.
The snippet I am using is:
public partial class AppDelegate : NSApplicationDelegate
{
public AppDelegate ()
{
}
public override void FinishedLaunching (NSObject notification)
{
// Construct menu that will be displayed when tray icon is clicked
var notifyMenu = new NSMenu();
var exitMenuItem = new NSMenuItem("Quit",
(a,b) => { System.Environment.Exit(0); }); // Just add 'Quit' command
notifyMenu.AddItem(exitMenuItem);
// Display tray icon in upper-right-hand corner of the screen
var sItem = NSStatusBar.SystemStatusBar.CreateStatusItem(30);
sItem.Menu = notifyMenu;
sItem.Image = NSImage.FromStream(System.IO.File.OpenRead(
NSBundle.MainBundle.ResourcePath + #"/menu_connected.png"));
sItem.HighlightMode = true;
// Remove the system tray icon from upper-right hand corner of the screen
// (works without adjusting the LSUIElement setting in Info.plist)
NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.Accessory;
}
}
Does anyone know of a good way of creating a windowless application in MonoMac that doesn't have a dock icon and only a menu bar icon?
Thanks,
BB
Try specifying a .xib for the "Main nib file name'
I did this some time ago, and it works fine for me. Something like this:
New monomac project
Created an 'AppController' class in C#:
[Register("AppController")]
public partial class AppController : NSObject
{
public AppController()
{
}
public override void AwakeFromNib()
{
var statusItem = NSStatusBar.SystemStatusBar.CreateStatusItem(30);
statusItem.Menu = statusMenu;
statusItem.Image = NSImage.ImageNamed("f3bfd_Untitled-thumb");
statusItem.HighlightMode = true;
}
In MainMenu.xib, I deleted the application menu
In MainMenu.xib, I added an custom object and set it's type to AppController
I created my status menu in the .xib and then connected it to the AppController with an outlet
In info.plist, I add the "Application is agent (UIElement)" value as a string and set it to "1"
Try it out with a .xib. If it doesn't work, maybe I can share my project for you to take apart.