I'm trying to style the UINavigationBar in Xamarin with MonoTouch. In the constructor of the UIViewController I tried the following:
//this.NavigationController.NavigationBar.TintColor = UIColor.Magenta;
UINavigationBar.Appearance.TintColor = UIColor.Yellow;
But if I try to run this in the simulator there is nothing changed. Where should I place this code? How do I use a RGB color (with UIColor.FromRGB (0, 127, 14)?) Is my code correct?
My Solution:
//AppDelegate.cs
public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
public static UIStoryboard Storyboard = UIStoryboard.FromName ("MainStoryboard", null);
public static UIViewController initialViewController;
// ...
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
initialViewController = Storyboard.InstantiateInitialViewController () as UIViewController;
UINavigationBar.Appearance.SetTitleTextAttributes (
new UITextAttributes () { TextColor = UIColor.FromRGB (0, 127, 14) });
window.RootViewController = initialViewController;
window.MakeKeyAndVisible ();
return true;
}
}
Assuming that you're developing for iOS7 you need to set BarTintColor.
UINavigationBar.Appearance.BarTintColor = UIColor.Red;
UINavigationBar.Appearance.BarTintColor = UIColor.FromRGB(0, 127, 14);
see: How to change UINavigationBar background color from the AppDelegate
Put this code in AppDelegate.cs
Try this ..
NSDictionary *textTitleOptions = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor darkGrayColor], UITextAttributeTextColor, [UIColor whiteColor], UITextAttributeTextShadowColor, nil];
[[UINavigationBar appearance] setTitleTextAttributes:textTitleOptions];
Or you can refer more from
IOS 7 Navigation Bar text and arrow color
You should specific the UIViewController, like:
viewController.navigationBar.tintColor = [UIColor yellowColor];
or in UIViewController:
self.navigationBar.tintColor = [UIColor yellowColor];
Related
I created a collectionview acting like a barchart diagram. For the bar display in the center of the screen, I am showing the current value for that center item. Everything works fine so far, but to be able to scroll the first or last item in the chart, to the center of the screen, i have to add padding to the beginning and end of the collection.
This chart is a migration of an old xamarin.forms app, where the padding was handle by a customerender and worked fine.
The issue i am currently seeing, is that when the collectionview´s ItemsLayout is
ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal)
the handler that i made, doesn't set the padding.
But if the
ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical)
it works fine.
I tried different approach with handlers
Microsoft.Maui.Controls.Handlers.Items.CollectionViewHandler.Mapper[nameof(IView)] = (h, v) =>
{
if (v is CollectionViewChart)
{
#if ANDROID
(h.PlatformView as Android.Views.View).SetPadding(375,0,375,0);
var recycleView = h.PlatformView;
recycleView.SetClipToPadding(false);
recycleView.SetPadding(375, 0, 375, 0);
#endif
}
#if IOS
h.PlatformView.SemanticContentAttribute = UISemanticContentAttribute.ForceRightToLeft;
((UICollectionView)h.PlatformView.Subviews[0]).CollectionViewLayout.CollectionView.ContentInset = new UIEdgeInsets(0, 375, 0, (float)375);
((UICollectionView)h.PlatformView.Subviews[0]).CollectionViewLayout.CollectionView.ContentOffset = new CoreGraphics.CGPoint(0, 0);
#endif
};
or like handlers that looks more like the old customrenders that i have from the xamarin.forms project, like this.
public partial class CollectionViewChartHandler : CollectionViewHandler
{
protected override void ConnectHandler(RecyclerView platformView)
{
platformView.RootView.SetPadding(375, 375, 375, 375);
platformView.SetClipToPadding(false);
platformView.SetPadding(375, 375, 375, 375);
base.ConnectHandler(platformView);
}
}
and for iOS
public partial class CollectionViewChartHandler : CollectionViewHandler
{
protected override void ConnectHandler(UIView platformView)
{
base.ConnectHandler(platformView);
platformView.SemanticContentAttribute = UISemanticContentAttribute.ForceRightToLeft;
(((UICollectionView)platformView.Subviews[0]).CollectionViewLayout.CollectionView).ContentInset = new UIEdgeInsets(0, 375, 0, (float)375);
((UICollectionView)platformView.Subviews[0]).CollectionViewLayout.CollectionView.ContentOffset = new CoreGraphics.CGPoint(0, 0);
}
}
But none seems to work, when the itemslayout of the collectionView is set to Horizontal, but works fine if the itemslayout is set to Vertical
Any idea why?
I tried to remove the border below the UINavigationBar as described here:
NavigationController.NavigationBar.SetBackgroundImage (new UIImage (), UIBarMetrics.Default);
NavigationController.NavigationBar.ShadowImage = new UIImage ();
In the app delegate I also set a background color:
UINavigationBar.Appearance.BackgroundColor = UIColor.FromRGB (247, 247, 247);
Now the UINavigationBar has no border as desired and also the color of the navigation bar has changed. But now the status bar is completely black not showing anything. I tried to set the style of the status bar in the Info.plist but that didn't helped either.
What I'm doing wrong? Do I have to set the background for the status bar somehow?
Now I tried to do that in a separate project and set the background color of the navigation bar. Here the status bar isn't black but the color for the status bar is gone. Only the navigation bar had a color, but the status bar stayed white. Normally through setting the bar tint color the status bar and the navigation bar should get the same color. E.g.
[[UINavigationBar appearance] setBarTintColor:[UIColor yellowColor]];
Setting the bar tint color didn't had an effect so I set the background color of the navigation bar.
How do I remove the border of the navigation bar and set the status and navigation bar to the same color?
I can't remember where I got this but I think it was in obj-c, it's what I use.
public static class UINavigationBarExtensions
{
public static void RemoveShadowImage(this UINavigationBar navigationBar)
{
foreach (var image in
from subView in navigationBar.Subviews
select subView as UIImageView
into imageView
where imageView != null && imageView.ToString()
.Contains("BarBackground")
from image in imageView.Subviews.OfType<UIImageView>()
.Where(image => Math.Abs(image.Bounds.Height - 0.5) < float.Epsilon)
select image)
image.RemoveFromSuperview();
}
}
Because the other approaches didn't worked as expected I now create an image and set this as background for the navigation bar like so:
UIImage backgroundImage = ImageHelper.ImageWithColor (UINavigationBar.Appearance.BarTintColor, new CGRect (0, 0, 1, 1));
NavigationController.NavigationBar.SetBackgroundImage (backgroundImage, UIBarMetrics.Default);
NavigationController.NavigationBar.ShadowImage = new UIImage ();
and here the ImageHelper class:
using System;
using System.Drawing;
using CoreGraphics;
using Foundation;
using UIKit;
public class ImageHelper
{
public ImageHelper ()
{
}
public static UIImage ImageWithColor(UIColor color, CGRect rect){
CGRect rectangleForImage = new CGRect (0, 0, rect.Width, rect.Height);
UIGraphics.BeginImageContext (rectangleForImage.Size);
CGContext context = UIGraphics.GetCurrentContext ();
context.SetFillColor (color.CGColor);
context.FillRect (rectangleForImage);
UIImage image = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();
return image;
}
}
I created custom class LoginView.cs UIView For username and password added the loginButton.
now I added UIView Call into my LoginViewController.cs Class
When i build and run the application it shows the login box, two text fields and a button. The actions on the textfield are not working. When the textbox has focus the keyboard doesn't load
This is my custom View class for loginview.cs
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace DemoHouse
{
class LoginView : UIView
{
UIView view_Login;
UITextField txt_username;
public readonly UITextField txt_password;
public readonly UIButton btn_Login;
public LoginView (string loginView){
float frame = UIScreen.MainScreen.Bounds.Width;
Add (view_Login = new UIView (new RectangleF (20, 60,frame-40, 200)) {
BackgroundColor = UIColor.Red,
});
float subFrame = view_Login.Bounds.Width;
view_Login.AddSubview(txt_username = new UITextField (new RectangleF (20, 20, subFrame-40, 31)){
BackgroundColor = UIColor.White,
});
view_Login.AddSubview(txt_password = new UITextField (new RectangleF (20, 70, subFrame-40, 31)){
BackgroundColor = UIColor.White
});
view_Login.AddSubview (btn_Login = new UIButton (new RectangleF (20, 120, 60, 31)) {
BackgroundColor = UIColor.Blue
});
}
}
}
This is LoginViewController.cs
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace DemoHouse
{
public partial class LoginViewController : UIViewController
{
LoginView loginView;
UIScrollView scrollView;
public override void DidReceiveMemoryWarning (){
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
#region View lifecycle
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
loginView = new LoginView("LoginView");
View.AddSubview (loginView);
// Perform any additional setup after loading the view, typically from a nib.
}
Let me know if something is wrong.
Is this the correct approach?
I do not want to use storyboard and xib in my application.
#All
Thanks in advance.
Might be a silly solution, but add a tap gesture to the button.
login_btn.UserInteractionEnabled = true;
login_btn.AddGestureRecognizer (new UITapGestureRecognizer(()=>{
//Action In HERE
}));
The keyboard popping up is a native functionality, so I am in awe you managed to break it. Maybe you should try not to condensate your code so much. It makes for less lines of code, but also causes readability and complexity to increase. Also, why not merge both classes? You already have a ViewController class. Try something like this:
public partial class LoginViewController : UIViewController
{
private UIScrollView scrollView;
private UITextField txt_username, txt_password;
private UIButton btn_login;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
/*Depending on what else is on the screen, you can hard-code the
x, y, width and height, but in all other cases, use this:*/
scrollView = new UIScrollView (this.View.Bounds);
txt_username = new UITextField (new RectangleF (5, 5, 50, 25));
//Change other properties of the UITextfield to your liking here.
txt_password = new UITextField (new RectangleF (5, 35, 50, 25));
//Change other properties of the UITextfield to your liking here.
btn_login = new UIButton (new RectangleF (5, 65, 50, 25));
btn_login.TouchUpInside += Login;
//Change other properties of the UIButton to your liking here.
this.View.AddSubview (scrollView);
scrollView.AddSubviews (new UIView[]{txt_username, txt_password, btn_login});
}
void Login (object sender, eventargs e)
{
//Do something on button click
}
}
Keep in mind that with this solution, you won't actually be able to scroll down with the scrollView, because the scrollView.ContentSize is not set. You could implement a method, where the framesizes of all controls are set. You call this method when changing orientation (in the ViewDidRotate method). You can also add the scrollView.ContentSize in this method.
I hope this information helps. Good luck!
I am trying to create a custom UIButton which extends from UIButtonType.RoundedRect.
My added functionality is working, but there is an issue with the initial rounded border state of my button. The border of my extended button is not drawn until after it has been tapped.
Update (January 24th 2013): Added the result of red background test, as requested by Richard Marskell, which concludes only the label of the button is drawn. BackgroundColor = UIColor.Red;
Below is my source code for creating my custom button.
public class TestView : UIView
{
public TestView(IntPtr p) : base(p) { }
public TestView(RectangleF bounds)
{
Frame = bounds;
BackgroundColor = UIColor.White;
UIButton button1 = new UIButton(UIButtonType.RoundedRect);
button1.Frame = new RectangleF(20,20,100,50);
button1.SetTitle("Button 1", UIControlState.Normal);
AddSubview(button1); // Drawn Correctly
MyButton button2 = new MyButton();
button2.Frame = new RectangleF(20,90,100,50);
button2.SetTitle("Button 2", UIControlState.Normal);
AddSubview(button2); // Only drawn correctly after Tap
// EDIT: Added to test Miguel's theory
UIButton button3 = UIButton.FromType(UIButtonType.RoundedRect);
button3.Frame = new RectangleF(20,160,100,50);
button3.SetTitle("Button 3", UIControlState.Normal);
AddSubview(button3); // Drawn Correctly
}
}
public class MyButton : UIButton
{
public MyButton() : base(UIButtonType.RoundedRect) { }
}
I'm just not sure how to force the border to be drawn correctly on loading of the view.
I don't need a button of type UIButtonType.Custom, as I don't want to style the button myself.
When I debug I the type of MyButton is correctly set to UIButtonType.RoundedRect.
The UIButton base properties of MyButton (button2) match the properties of the UIButton instance (button1).
How can I resolve this issue?
Update (January 31st 2013): Herman Schoenfeld provided a suitable solution for this bug.
This works
public class MyButton : UIButton
{
public MyButton() : base(UIButtonType.RoundedRect) { }
public override RectangleF Frame {
get {
return base.Frame;
}
set {
var temp = TranslatesAutoresizingMaskIntoConstraints;
TranslatesAutoresizingMaskIntoConstraints = false;
var constraints = new [] {
NSLayoutConstraint.Create(this, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, value.Width),
NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, value.Height)
};
AddConstraints(constraints);
SizeToFit();
RemoveConstraints(constraints);
base.Frame = value;
TranslatesAutoresizingMaskIntoConstraints = temp;
}
}
}
This is only a workaround, it appears to be a bug. The SizeToFit() fixes the issue, the other code maintains the frame.
I have created a simple custom panel using ContainerControl as my base. I've added custom properties to create borders and gradient backgrounds. If I override OnPaint and OnPaintBackground all child controls of the parent inherit the gradient and border styles. As a work around I have used the parents BackgroundImage property which works fine but has a few random quirks. There has to be a better way of approaching this issue but I have found no solution. Are there any Window API functions via Interop or other C# methods to fix this? If so please provide an example.
EDIT! Here is the style being copied (ugly example but makes the point):
EDIT 2! Here is a simple hard-coded ContainerControl without all the properties, designer attributes, etc.
public class Container : ContainerControl
{
protected override void OnPaintBackground( PaintEventArgs e )
{
using ( var brush = new LinearGradientBrush( e.ClipRectangle, Color.Red, Color.Blue, LinearGradientMode.Vertical ) )
{
e.Graphics.FillRectangle( brush, e.ClipRectangle );
}
}
}
If a Label control is created with its BackColor property set to Color.Transparent, it will end up calling its parent's OnPaintBackground() implementation.
If you modify Jon's example like this:
var label = new Label {
Text = "Label",
Location = new Point(20, 50),
BackColor = Color.Transparent
};
Then you will reproduce the issue.
There is an easy workaround, however. The problem comes from the way you're creating the linear gradient brush. Since you're passing e.ClipRectangle to its constructor, the shape of the gradient will vary depending on the control being rendered (container or label). On the other hand, if you pass the ClientRectangle of the container, then the gradient will always have the same shape and the result should be what you're looking for:
protected override void OnPaintBackground(PaintEventArgs e)
{
using (var brush = new LinearGradientBrush(ClientRectangle,
Color.Red, Color.Blue, LinearGradientMode.Vertical)) {
e.Graphics.FillRectangle(brush, e.ClipRectangle);
}
}
The result is:
Initialize the properties on control create/load
Then "INVALIDATE" the control to force a redraw of the control
I can't reproduce this simply on my Windows 7 machine - which suggests it may be one of the properties you've set in the designer. Short but complete program:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class GradientContainer : ContainerControl
{
protected override void OnPaintBackground(PaintEventArgs e)
{
using (var brush = new LinearGradientBrush(e.ClipRectangle,
Color.Red, Color.Blue, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(brush, e.ClipRectangle);
}
}
}
class Test
{
static void Main()
{
var label = new Label {
Text = "Label",
Location = new Point(20, 50)
};
var container = new GradientContainer {
Size = new Size(200, 200),
Location = new Point(0, 0),
Controls = { label }
};
Form form = new Form {
Controls = { container },
Size = new Size(300, 300)
};
Application.Run(form);
}
}
And the result: