How to Change Title Kerning Value of NavigationBar in iOS using Xamarin - ios

I'm trying to adjust the kerning for the title text in the NavigationBar. I've gotten as far as assigning a custom UIStringAttributes to the NavigationBar title. Setting the font and the text color seems to work fine, but when I input the Kerning Adjustment, nothing happens, regardless of what value I input.
public void SetTitleFont (string fontName, float fontSize, Color foregroundColor)
{
var TitleAttr = new UIStringAttributes {
ForegroundColor = foregroundColor.ToUIColor(),
Font = UIFont.FromName (fontName, fontSize),
KerningAdjustment = 50
};
this.NavigationController.NavigationBar.TitleTextAttributes = TitleAttr;
}

Figured this one out.
What worked out for me was creating a new UILabel, set the attributes for the UILabel, then set the TitleView to the UILabel.
// We will grab the actual title of the Page further down.
string viewTitle = string.Empty;
UINavigationItem navItem = new UINavigationItem();
if (this.NavigationController != null)
{
if (this.NavigationController.VisibleViewController != null)
{
if (this.NavigationController.VisibleViewController.NavigationItem != null)
{
navItem = this.NavigationController.VisibleViewController.NavigationItem;
// Grab the title of the Page you are on.
if (navItem.Title != null)
{
viewTitle = this.NavigationController.VisibleViewController.NavigationItem.Title;
}
}
}
}
// We do not want to set an arbitrary size for the UILabel.
// Otherwise, positioning it will be very difficult.
// The StringSize function will set the size of the UILabel to the absolute
// minimum size of whatever string you specify - given the correct
// parameters (font and fontSize).
CGSize titleSize = viewTitle.StringSize(UIFont.FromName (fontName, size));
// Create the new title UILabel. Make sure to set the Bounds!
pageTitleView = new UILabel {
Bounds = new CGRect (0, 0, titleSize.Width, titleSize.Height),
BackgroundColor = UIColor.FromRGBA(0, 0, 0, 0)
};
var titleAttributes = new NSAttributedString (viewTitle,
new UIStringAttributes () {
ForegroundColor = foregroundColor.ToUIColor(),
Font = UIFont.FromName (fontName, size),
KerningAdjustment = 1.1f
});
// Apply the new attributes to the UILabel and center the text.
pageTitleView.AttributedText = titleAttributes;
pageTitleView.TextAlignment = UITextAlignment.Center;
// Set the TitleView to the new UILabel.
navItem.TitleView = pageTitleView;
I hope this helps!

Related

How to render a UIButton in Xamarin.iOS

How do I render a UIButton in Xamarin.iOS? See the current Code for the full list.
This is the code I'm using to create and add the button to the Xamarin.Forms.Platform.iOS.CellTableViewCell cell. I cannot get the button to display anything.
With the use of a Foundation.NSMutableAttributedString, it shows a cut-off section of text in the top left corner, regardless of anything I try (alignments, insets, bounds, various constraints, etc). I'm currently trying things from Xamarin.Forms.Platform.iOS.Renderers.ButtonRenderer, but still can't get anything to display at all, no text, no button, or its outline.
If you could fork the repo and fix it or post the solution here, I would be very grateful.
protected override void SetUpContentView()
{
var insets = new UIEdgeInsets(SVConstants.Cell.PADDING.Top.ToNFloat(), SVConstants.Cell.PADDING.Left.ToNFloat(), SVConstants.Cell.PADDING.Bottom.ToNFloat(), SVConstants.Cell.PADDING.Right.ToNFloat());
_Button = new UIButton(UIButtonType.RoundedRect)
{
AutoresizingMask = UIViewAutoresizing.All,
HorizontalAlignment = UIControlContentHorizontalAlignment.Center,
VerticalAlignment = UIControlContentVerticalAlignment.Center,
ContentEdgeInsets = insets,
// TitleEdgeInsets = insets
};
DefaultFontSize = _Button.TitleLabel.ContentScaleFactor;
DefaultTextColor = _Button.TitleLabel.TextColor;
_Recognizer = new UILongPressGestureRecognizer(RunLong);
_Button.TouchUpInside += OnClick; // https://stackoverflow.com/a/51593238/9530917
_Button.AddGestureRecognizer(_Recognizer); // https://stackoverflow.com/a/6179591/9530917
ContentView.AddSubview(_Button);
_Button.CenterXAnchor.ConstraintEqualTo(ContentView.CenterXAnchor).Active = true;
_Button.CenterYAnchor.ConstraintEqualTo(ContentView.CenterYAnchor).Active = true;
_Button.WidthAnchor.ConstraintEqualTo(ContentView.WidthAnchor).Active = true;
_Button.HeightAnchor.ConstraintEqualTo(ContentView.HeightAnchor).Active = true;
UpdateConstraintsIfNeeded();
LayoutIfNeeded();
}
Found out that you can't subclass it. Any button added to the view must be native (UIButton) or custom rendered, such as Xamarin.Forms.Platform.iOS.ButtonRenderer; It doesn't show up otherwise.

Views in UIStackviews have ambiguous Width

I have the following code that seems to work fine but suffers from constraints problems:
UIView container = something;
UIView bottomAnchorView = previewViewInSameContainer;
var itemAsAWhole = new UIStackView { TranslatesAutoresizingMaskIntoConstraints = false, Axis = UILayoutConstraintAxis.Horizontal, Distribution = UIStackViewDistribution.Fill, Alignment = UIStackViewAlignment.Fill };
var itemTitle = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false, Text = title, Font = FontHelpers.GenerateUIFont("Ubuntu-Light", UIFontTextStyle.Body) };
itemTitle.Tag = itemTitle.GenerateViewTag();
var scoreHStack = new UIStackView { TranslatesAutoresizingMaskIntoConstraints = false, Axis = UILayoutConstraintAxis.Horizontal, Distribution = UIStackViewDistribution.Fill, Alignment = UIStackViewAlignment.Fill };
var itemScore = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false, Text = score == -1 ? "-" : score.ToString(), MinimumFontSize = 8, TextColor = Utilities.GetNoteColorFromScoreValue(score), Font = FontHelpers.GenerateUIFont("Ubuntu-Medium", UIFontTextStyle.Title2) };
itemScore.Tag = itemScore.GenerateViewTag();
var maxScore = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false, Text = "/10", Font = FontHelpers.GenerateUIFont("Ubuntu-Light", UIFontTextStyle.Body) };
scoreHStack.AddArrangedSubview(itemScore);
scoreHStack.AddArrangedSubview(maxScore);
itemAsAWhole.AddArrangedSubview(itemTitle);
itemAsAWhole.AddArrangedSubview(scoreHStack);
container.AddSubview(itemAsAWhole);
itemAsAWhole.TopAnchor.ConstraintEqualTo(bottomAnchorView.BottomAnchor).Active = true;
itemAsAWhole.LeadingAnchor.ConstraintEqualTo(container.LeadingAnchor).Active = true;
itemAsAWhole.TrailingAnchor.ConstraintEqualTo(container.TrailingAnchor).Active = true;
At runtime:
The itemTitle UILabel has ambiguous Width.
The scoreHStack UIStackView has ambiguous Width and horizontal position.
The itemScore UILabel has ambiguous Width.
the maxScore UILabel has ambiguous Width and horizontal position.
What Am I missing in the code to make those warnings disappear?
EDIT : Here is a screenshot of what it does:
EDIT 2 : Problem solved with the help of another answer. Thank you #DonMag ;)
var itemScore = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false, Text = score == -1 ? "-" : score.ToString(), MinimumFontSize = 8, TextColor = Utilities.GetNoteColorFromScoreValue(score), Font = FontHelpers.GenerateUIFont("Ubuntu-Medium", UIFontTextStyle.Title2) };
itemScore.SetContentHuggingPriority(1000f, UILayoutConstraintAxis.Horizontal);
itemScore.SetContentCompressionResistancePriority(1000f, UILayoutConstraintAxis.Horizontal);
itemScore.Tag = itemScore.GenerateViewTag();
var maxScore = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false, Text = "/10", Font = FontHelpers.GenerateUIFont("Ubuntu-Light", UIFontTextStyle.Body) };
maxScore.SetContentHuggingPriority(1000f, UILayoutConstraintAxis.Horizontal);
maxScore.SetContentCompressionResistancePriority(1000f, UILayoutConstraintAxis.Horizontal);
scoreHStack.AddArrangedSubview(itemScore);
scoreHStack.AddArrangedSubview(maxScore);
itemAsAWhole.AddArrangedSubview(itemTitle);

Vertical UIStackView alignment

I have a vertical UIStackview with 3 controls in it.
I want all the controls to be centered, and the first two to expand the whole width available. The third one should take 80% of the available width and be centered as well.
Here is the result I got so far:
As you can see the third control is left aligned.
Here is the code I have for all of this:
var container = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Vertical,
Distribution = UIStackViewDistribution.EqualCentering,
Alignment = UIStackViewAlignment.Fill,
Spacing = 10f
};
// Create the Title
UILabel title = new UILabel
{
TranslatesAutoresizingMaskIntoConstraints = false,
Text = item.name,
TextAlignment = UITextAlignment.Center,
Lines = 2,
};
container.AddArrangedSubview(title);
// Create the gauge
SFCircularGauge circularGauge = new SFCircularGauge { TranslatesAutoresizingMaskIntoConstraints = false };
circularGauge.Tag = circularGauge.GenerateViewTag();
circularGauge.HeightAnchor.ConstraintEqualTo(100f).Active = true;
#if DEBUG
circularGauge.BackgroundColor = UIColor.Cyan;
#endif
container.AddArrangedSubview(circularGauge);
// Add the evaluate button
var evaluate = UIButton.FromType(UIButtonType.RoundedRect);
evaluate.TranslatesAutoresizingMaskIntoConstraints = false;
evaluate.SetTitle(Utilities.GetLocalizedString("qol_rate_button_text"), UIControlState.Normal);
evaluate.SetTitleColor(UIColor.White, UIControlState.Normal);
evaluate.BackgroundColor = new UIColor(red: 1.00f, green: 0.37f, blue: 0.00f, alpha: 1.0f); // Optimistic Orange
evaluate.Layer.CornerRadius = 5f;
evaluate.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
evaluate.ContentEdgeInsets = new UIEdgeInsets(top: 0, left: 10f, bottom: 0, right: 10f);
evaluate.UserInteractionEnabled = true;
evaluate.TouchUpInside -= Evaluate_TouchUpInside;
evaluate.TouchUpInside += Evaluate_TouchUpInside;
evaluate.Tag = evaluate.GenerateViewTag();
viewIdsAutoEvalsIds.Add((int)evaluate.Tag, item.id);
container.AddArrangedSubview(evaluate);
evaluate.WidthAnchor.ConstraintEqualTo(container.WidthAnchor, 0.8f).Active = true;
evaluate.CenterXAnchor.ConstraintEqualTo(container.CenterXAnchor).Active = true;
I can't figure out where is my problem. In the UIStackView configuration? Somewhere else?
Thanks in advance.
The property Alignment is to sets the alignment of the non-axial subviews . In your case , you need to set it as
UIStackViewAlignment.Center
instead of
UIStackViewAlignment.Fill
This might be a bug of the control. We'll see.
In the meantime, thanks again to the Reveal Tool, the gauge has no width defined.
I solved the problem by setting the width constraint explicitly:
// Fix the width to be 100% of the container
circularGauge.WidthAnchor.ConstraintEqualTo(container.WidthAnchor).Active = true;

Tab bar not using full width on iOS11 iPad

I'm using a UITabbarViewController in a relatively simple way. My issue only appears on iPad devices of iOS11 version. It's not visible on iOS10 or iPhone.
If you look at the screenshot, you can see that the background color of the tab is not aligned. Actually, it is aligned, it's the tabbar itself that is not taking the full width. So the background color is overlapping towards the central button because it's not using the space on the far left and far right.
I'm assuming that the tabbar is broken (and not my background colors, which are drawn manually) because the edges of the outsides tabs are not clickable, and yet the item positioning is set to be filling the width of the screen :
TabBar.ItemPositioning = UITabBarItemPositioning.Fill;
The items sizes are wrong if you consider the tabbar fullscreen, but they are if you consider the "reduced" version. So i'm pretty sure it's all good there, as long as the tabbar decides to take the full width of the screen, the buttons and background color will then have the correct measurements.
I've tried using View.LayoutIfNeeded() and SetNeedsLayout() to force a redraw, but to no avail.
I'm not sure why it's even behaving like so, and since it's the default behaviour of the OS and I haven't done anything particular, I'm not certain of what can even be tried.
Here's some relevant code :
MainTabbarController tabController = (MainTabbarController)Window.RootViewController;
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
ConfigureTabbar();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
UIViewController[] tabs = //Create the VCs in the most basic way
SetViewControllers(tabs, false);
}
protected virtual void ConfigureTabbar()
{
TabBar.Translucent = false;
TabBar.ItemPositioning = UITabBarItemPositioning.Fill;
TabBar.ItemSpacing = 0;
//View.LayoutIfNeeded();
float tabbarItemWidth = (float)Math.Ceiling(View.Bounds.Width / TabBar.Items.Length) + 1; //+ 1 to avoid the right pixel that was not filled on the right tab. Strange behaviour...
TabBar.ItemWidth = tabbarItemWidth;
//var version = NSProcessInfo.ProcessInfo.OperatingSystemVersion;
NSOperatingSystemVersion ios11 = new NSOperatingSystemVersion(11, 0, 0);
if (NSProcessInfo.ProcessInfo.IsOperatingSystemAtLeastVersion(ios11))
{
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGRect(0, -View.SafeAreaInsets.Bottom, tabbarItemWidth, TabBar.Frame.Height));
}
else
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGRect(0, -View.SafeAreaInsets.Bottom, tabbarItemWidth, TabBar.Frame.Height));
}
}
else
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGSize(tabbarItemWidth, TabBar.Frame.Height));
}
UITextAttributes attrs = new UITextAttributes();
attrs.Font = _viewModel.Styles.Fonts.ExtraSmall.ToNative();
attrs.TextColor = _viewModel.Styles.Colors.ActionText.ToNative();
UITabBarItem.Appearance.SetTitleTextAttributes(attrs, UIControlState.Normal);
for (int i = 0; i < TabBar.Items.Length; i++)
{
UITabBarItem item = TabBar.Items[i];
item.Title = _viewModel.Titles[i];
item.TitlePositionAdjustment = new UIOffset(0, -4);
item.ImageInsets = new UIEdgeInsets(-2, 0, 2, 0);
}
//View.LayoutIfNeeded();
}

Xamarin FlyoutNavigationController does not show section FooterView

I want to implement a flyout navigation in Xamarin.iOS. For this purpose I am using the FlyoutNavigationController, which works good so far.
But now I have to display some additional content underneath the navigation list inside of the flyout-menu (basically an image, some labels and buttons). For this purpose, I wanted to use the FooterView property of the "section" control that holds the menu items.
When I set
section.Footer = "Test";
it will work (I can see the text), but when I use the 'FooterView' property, nothing shows up:
public class ViewController : UIViewController
{
FlyoutNavigationController navigation;
private const string PageNamePage1 = "The first page";
private const string PageNamePage2 = "The second page";
readonly string[] pages =
{
PageNamePage1,
PageNamePage2
};
public override void ViewDidLoad()
{
base.ViewDidLoad();
navigation = new FlyoutNavigationController
{
View =
{
Frame = UIScreen.MainScreen.Bounds
}
};
View.AddSubview(navigation.View);
var elements = pages.Select(page => new StringElement(page) as Element);
navigation.NavigationRoot = new RootElement("Induserv App");
var section = new Section();
section.AddAll(elements);
var uiTextView = new UITextView {Text = "--> This won't show!"};
section.FooterView = new UIView
{
uiTextView
};
navigation.NavigationRoot.Add(section);
navigation.ViewControllers = new UIViewController[]
{
new UINavigationController(new Page1Controller(navigation, PageNamePage1)),
new UINavigationController(new Page2Controller(navigation, PageNamePage2)),
};
}
}
Does anyone have an idea what it needs to display this footer here? Is there another way to put some controls in this panel?
Set a frame for both the footer view and uiTextView, like so:
var uiTextView = new UITextView(new RectangleF(0, 0, 10, 10)) {Text = "--> This won't show!"};
section.FooterView = new UIView(new RectangleF(0, 0, 10, 10))
{
uiTextView
};

Resources