I'm using Xamarin.Forms and on iOS I need to customize the top action bar.
In this case I need to remove the dark line between the top action bar and the content view below (see screen shot).
How can I do it ?
Thank you in advance!!
I did it here and it working:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
//Tab bar
UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(247, 139, 43);
//Switch
UISwitch.Appearance.OnTintColor = UIColor.FromRGB(247, 139, 43);
//----------------------------------------------------------------------------
UINavigationBar.Appearance.BarTintColor = UIColor.Clear;
UINavigationBar.Appearance.ShadowImage = new UIImage();
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
//----------------------------------------------------------------------------
global::Xamarin.Forms.Forms.Init();
ImageCircleRenderer.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
You can achieve this by either creating a custom Renderer:
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationRenderer))]
namespaceiOS.Renderers
{
public class CustomNavigationRenderer : NavigationRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.NavigationBar.ShadowImage = new UIImage();
this.NavigationBar.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
}
}
}
Or in your iOS project, in AppDelegate method "FinishedLaunching" you could use the UIAppearance API to style your application across the board.
UINavigationBar.Appearance.ShadowImage = new UIImage();
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
Related
I have a Xamarin.Forms app. I would like to remove/hide the back arrow in my navigation bars but keep the title. I was able to do it in iOS using the following code inside my NavigationPageRenderer:
UINavigationBar.Appearance.BackIndicatorImage = new UIImage();
UINavigationBar.Appearance.BackIndicatorTransitionMaskImage = new UIImage();
Is there any equivalent code for this in Android that I could use inside my renderer or in the MainActivity? I tried this.ActionBar.SetDisplayHomeAsUpEnabled(false); inside my MainActivity but the ActionBar always returns null. Below is my my MainActivity code:
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
if (Window != null)
{
Window.SetStatusBarColor(Android.Graphics.Color.Transparent);
}
this.ActionBar.SetDisplayHomeAsUpEnabled(false);
}
}
What I want my navigation bar to look like something like the image below (this is in my iOS app).
The back arrow is just the back button title: NavigationPage.SetBackButtonTitle(this, "\u25C3");
In my ContentPage:
public partial class HomeTabPage : ContentPage
{
public HomeTabViewModel vm;
public HomeTabPage()
{
InitializeComponent();
BindingContext = vm = new HomeTabViewModel(this);
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetBackButtonTitle(this, "\u25C3");
}
}
Solution:
You can define a custom view as navigationBar of your content on specific platform (Android).Refer to the following code.
public partial class Page1 : ContentPage
{
public Page1 ()
{
InitializeComponent ();
if(Device.RuntimePlatform=="Android")
{
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetTitleView(this, SetBackView("Title", "back"));
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
Navigation.PopAsync();
}
StackLayout SetBackView (string title,string backButtonContent)
{
Button backButton = new Button()
{
Text = backButtonContent,
TextColor = Color.White,
FontAttributes=FontAttributes.None,
BackgroundColor = Color.Transparent,
Margin = new Thickness(-20,0,0,0),
};
backButton.Clicked += BackButton_Clicked;
StackLayout stackLayout = new StackLayout
{
Children = {
backButton,
new Label{
HorizontalTextAlignment=TextAlignment.Center,
VerticalTextAlignment=TextAlignment.Center,
Text=title,
TextColor=Color.White,
BackgroundColor=Color.Transparent,
},
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Horizontal,
};
return stackLayout;
}
}
And the effect is just like the following ,you can set the content of page title and backButton as you want.
I want to open a UIViewController from a content page and this code helps me in doing this
UIWindow Window = new UIWindow(UIScreen.MainScreen.Bounds);
var cvc = new ScanningPage();
var navController = new UINavigationController(cvc);
Window.RootViewController = navController;
Window.MakeKeyAndVisible();
but I also want a Back button on that Controller Page which navigate me back to that content Page.
this.NavigationController.PopViewController(true);
or
this.DismissViewController(true,null);
not working in this case.
I would recommend not creating a new Window and a UINavigationController...
Xamarin.Forms is contained in a single VC in the first Window, so you can obtain that view controller via:
UIApplication.SharedApplication.Windows[0].RootViewController;
So as an example Dependency service that presents and dismisses a VC (either from Forms or the view controller), you can do something like this.
Dependency interface:
public interface IDynamicVC
{
void Show();
void Dismiss();
}
iOS Dependency implementation
public class DynamicVC : IDynamicVC
{
UIViewController vc;
public void Show()
{
if (vc != null) throw new Exception("DynamicVC already showing");
vc = new UIViewController();
var button = new UIButton(new CGRect(100, 100, 200, 200));
button.SetTitle("Back", UIControlState.Normal);
button.BackgroundColor = UIColor.Red;
button.TouchUpInside += (object sender, EventArgs e) =>
{
Dismiss();
};
vc.Add(button);
var rootVC = UIApplication.SharedApplication.Windows[0].RootViewController;
rootVC.PresentViewController(vc, true, () => { });
}
public void Dismiss()
{
vc?.DismissViewController(true, () =>
{
vc.Dispose();
vc = null;
});
}
}
In my Xamarin forms application I want to show a confirmation message when user clicks the back button from Main-page. Is there any way to achieve this?
I overrided the OnBackButtonPressed method in my MainPage. But still the app is closing while back key press. Here is my code
protected override bool OnBackButtonPressed ()
{
//return base.OnBackButtonPressed ();
return false;
}
You can override OnBackButtonPressed for any Xamarin.Form Page. But it only will work for the physical button in Android and Windows Phone devices.
protected override bool OnBackButtonPressed () {
DisplayAlert("title","message","ok");
return true;
}
For the virtual one, you will need to create CustomRenderers and to intercept the click handler. In iOS it can be tricky because the user can go back doing other actions (e.g. the swipe gesture). Once you intercept it you just need to create your Confirmation Message (which I assume that you know how to do it).
For iOS you can do something like this:
[assembly: ExportRenderer (typeof (YourPage), typeof (YourPageRenderer))]
namespace YourNamespace {
public class YourPageRenderer : PageRenderer {
public override void ViewWillAppear (bool animated) {
base.ViewWillAppear (animated);
Action goBack = () => page.DisplayAlert("title","message","ok");
var backButton = new NavBackButton (goBack);
navigationItem.LeftBarButtonItem = new UIBarButtonItem (backButton);
}
}
public class NavBackButton : UIView {
public NavBackButton (Action onButtonPressed) {
SetButton (onButtonPressed);
}
UILabel text;
UIImageView arrow;
void SetButton(Action onButtonPressed){
arrow = new UIImageView(new CGRect(-25,0, 50, 50)) {
Image = new UIImage("Images/back").ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
};
arrow.TintColor = Colors.DarkGreen.ToUIColor ();
text = new UILabel(new CGRect(arrow.Frame.Width + arrow.Frame.X -15, arrow.Frame.Height /2 - 10, 40, 20)) { Text = "Back" };
text.TextColor = Colors.DarkGreen.ToUIColor ();
Frame = new CGRect(0,0,text.Frame.Size.Width + arrow.Frame.Width, arrow.Frame.Height);
AddSubviews (new UIView[] { arrow, text });
var tapGesture = new UITapGestureRecognizer (onButtonPressed);
AddGestureRecognizer (tapGesture);
}
public override void TouchesBegan (Foundation.NSSet touches, UIEvent evt) {
base.TouchesBegan (touches, evt);
text.TextColor = UIColor.YourColor;
arrow.TintColor = UIColor.YourColor;
}
public override void TouchesEnded (Foundation.NSSet touches, UIEvent evt){
base.TouchesEnded (touches, evt);
arrow.TintColor = UIColor.YourColor;
text.TextColor = UIColor.YourColor;
}
}
}
PS You will need to provide an arrow image ("Images/back")
Using Xamarin, I am trying to create a UICollectionViewFlowLayout where my cells will be the width of the device and flow down vertically. Something like the Facebook news tab iOS app.
Currently to get the Cells in the layout, here is by code:
public override async void ViewWillAppear (bool animated)
{
try{
base.ViewWillAppear (animated);
var layout = new UICollectionViewFlowLayout ();
layout.MinimumInteritemSpacing = 30;
var collectionView = new NewsListView (UIScreen.MainScreen.ApplicationFrame, layout);
collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
collectionView.BackgroundColor = UIColor.LightGray;
collectionView.RegisterClassForCell (typeof(NewsListViewCell), cellId);
collectionView.ReloadData ();
CollectionView = collectionView;
Logger.Log(""+CollectionView.Bounds.Width);
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
I want to use this to set the size of the item:
layout.ItemSize = new CGSize (CollectionView.Bounds.Width-20, 200.0f);
But CollectionView does not exist yet when i am creating the UICollectionViewFlowLayout,
Is there any other way i can set the size of UICollectionViewFlowLayout to the width of the device?
I found a solution to my problem. I created the layout as a global variable and then added it to the view in ViewDidLoad (), then in ViewWillAppear(..) i can set layout.ItemSize
So my code will as follows:
UICollectionViewFlowLayout layout;
public override async void ViewDidLoad ()
{
try{
base.ViewDidLoad ();
Title = "News";
layout = new UICollectionViewFlowLayout ();
layout.MinimumInteritemSpacing = 30;
var collectionView = new NewsListView (UIScreen.MainScreen.ApplicationFrame, layout);
collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
collectionView.BackgroundColor = UIColor.LightGray;
collectionView.RegisterClassForCell (typeof(NewsListViewCell), cellId);
collectionView.ReloadData ();
CollectionView = collectionView;
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
public override async void ViewWillAppear (bool animated)
{
try{
base.ViewWillAppear (animated);
Logger.Log(""+CollectionView.Bounds.Width);
layout.ItemSize = new CGSize (CollectionView.Bounds.Width-20, 200.0f);
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
This way the item width of the layout is always based on device width and not hardcoded
I have looked around the web for some time looking for any resources on this topic and have come up with nothing that solves my dilemma.
I have a dialog view controller and its root is simply displaying a list of strings similar to how the iphone music song scrollable view is laid out. What I need is a subview located at the top of the screen and the scrollable DVC below it. I need to the top view to be always in view while the user can scroll through the root element because the top view will be holding statistics.
I have tried adding a subview but it simply overlaps the dvc below it, and I have not been able to figure out a way to add a dvc as a subview to a UIView.
Any help would be much appreciated.
What is needed to achieve this is a single root view controller that hosts two subview controllers. One subview contains the statistics at the top of the window. The bottom subview contains a navigation controller that holds the dialog view.
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.Dialog;
using System.Drawing;
namespace delete201205203
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
MyUIViewController _mvc;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
_mvc = new MyUIViewController ();
window.RootViewController = _mvc;
window.MakeKeyAndVisible ();
return true;
}
}
public class MyUIViewController : UIViewController
{
MyDialogViewController _dvc;
UINavigationController _nav;
StatisticsViewController _statistics;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var root = new RootElement ("Root") {
new Section ("Section") {
new EntryElement ("caption", "placeholder", ""),
new RootElement ("Root 2") {
new Section ("Section") {
new EntryElement ("caption", "placeholder", ""),
new StringElement ("Back", () => {
_nav.PopViewControllerAnimated (true);
})
}
}
}
};
_dvc = new MyDialogViewController (root);
_nav = new UINavigationController (_dvc);
_nav.SetNavigationBarHidden (true, false);
_nav.View.Frame = new RectangleF (0, 70f,
this.View.Bounds.Width,
this.View.Bounds.Height -70f);
_statistics = new StatisticsViewController ();
_statistics.View.Frame = new RectangleF (0, 0,
this.View.Bounds.Width,
70f);
this.AddChildViewController (_nav);
this.View.AddSubview (_nav.View);
this.AddChildViewController (_statistics);
this.View.AddSubview (_statistics.View);
}
public override void ViewWillLayoutSubviews ()
{
base.ViewWillLayoutSubviews ();
_nav.View.Frame = new RectangleF (0, 70f,
this.View.Bounds.Width,
this.View.Bounds.Height -70f);
_statistics.View.Frame = new RectangleF (0, 0,
this.View.Bounds.Width,
70f);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
public class StatisticsViewController : UIViewController
{
UILabel _label;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
this.View.BackgroundColor = UIColor.White;
_label = new UILabel (new RectangleF (this.View.Bounds.Width * .5f - 50f,
this.View.Bounds.Height * .5f -10f,
100f, 20f));
_label.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
_label.Text = "statistics";
this.View.AddSubview (_label);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
// This overrde is needed to ensure the pop view animation
// works correctly in landscape mode
public class MyDialogViewController : DialogViewController
{
public MyDialogViewController (RootElement root) : base (root) {}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
}