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);
Related
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;
I ported a table view implementation from Swift with a variable height cell. But in my Xamarin/ReactiveUI implementation, the cell does not resize when the content grows (i.e. when an optional label is displayed). Please note that the cell does resize to fit in the native Swift implementation.
Most answers online focus on the setting of two properties on UITableView: RowHeight and EstimatedHeight as well as using AutoLayout. My row height is set to UITableView.AutomaticDimension and the EstimatedHeight is set to 44f. I am using autolayout constraints which I will show below. I am using the BindTo extensions in ReactiveTableViewSourceExtensions.
I also tried setting the Text property of the optional label right away to test the theory that setting the property up front would provoke a resize.
Here are the pertinent lines of code:
In a ReactiveViewController<T> ctor:
this.WhenActivated(disposables =>
{
//// ...
// This method automatically wires up the cell reuse key to be the nameof my cell class which is what I want.
this.WhenAnyValue(view => view._cells)
.BindTo<IImportedFileViewModel, ImportedFileCell>(TableView, 44f)
.DisposeWith(disposables);
//// ...
});
Below in ViewDidLoad:
//// ...
TableView = new UITableView
{
RowHeight = UITableView.AutomaticDimension,
EstimatedRowHeight = 44f, // Setting or not setting this doesn't matter
SeparatorStyle = UITableViewCellSeparatorStyle.None,
AllowsSelection = false,
TranslatesAutoresizingMaskIntoConstraints = false,
};
//// ...
In the cell implementation:
ClipsToBounds = true;
PreservesSuperviewLayoutMargins = true;
ContentView.ClipsToBounds = true;
ContentView.PreservesSuperviewLayoutMargins = true;
var stackView = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Vertical,
Distribution = UIStackViewDistribution.Fill,
Alignment = UIStackViewAlignment.Fill,
Spacing = 4,
};
var fileStackView = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Horizontal,
Distribution = UIStackViewDistribution.Fill,
Alignment = UIStackViewAlignment.Top,
};
FilenameLabel = new UILabel
{
TranslatesAutoresizingMaskIntoConstraints = false,
Font = UIFont.SystemFontOfSize(15f, UIFontWeight.Medium),
};
fileStackView.AddArrangedSubview(FilenameLabel);
StatusImage = new UIImageView()
{
TranslatesAutoresizingMaskIntoConstraints = false,
ContentMode = UIViewContentMode.Center,
};
fileStackView.AddArrangedSubview(StatusImage);
stackView.AddArrangedSubview(fileStackView);
var reasonStackView = new UIStackView
{
TranslatesAutoresizingMaskIntoConstraints = false,
Axis = UILayoutConstraintAxis.Horizontal,
Distribution = UIStackViewDistribution.Fill,
Alignment = UIStackViewAlignment.Top,
};
// This is the optional label that, when its Text property is set, should resize the cell.
FailureReasonLabel = new UILabel
{
TranslatesAutoresizingMaskIntoConstraints = false,
Font = UIFont.SystemFontOfSize(13f, UIFontWeight.Medium),
Lines = 0,
};
reasonStackView.AddArrangedSubview(FailureReasonLabel);
stackView.AddArrangedSubview(reasonStackView);
ContentView.AddSubview(stackView);
stackView.BottomAnchor.ConstraintEqualTo(ContentView.LayoutMarginsGuide.BottomAnchor).Active = true;
stackView.TopAnchor.ConstraintEqualTo(ContentView.LayoutMarginsGuide.TopAnchor).Active = true;
stackView.LeadingAnchor.ConstraintEqualTo(ContentView.LayoutMarginsGuide.LeadingAnchor).Active = true;
stackView.TrailingAnchor.ConstraintEqualTo(ContentView.LayoutMarginsGuide.TrailingAnchor).Active = true;
StatusImage.HeightAnchor.ConstraintEqualTo(16f).Active = true;
StatusImage.WidthAnchor.ConstraintEqualTo(16f).Active = true;
I would be happy to get a solution to the problem using the basic structure I have now but I would also accept an example of some other pattern that someone has used (based on ReactiveUI) to get this working. I would prefer that the solution not be based on old manual resizing patterns like in the pre-iOS 8 days or some sort of hack.
So two things had to be adjusted to fix my issue.
The sizeHint parameter in the ReactiveUI BindTo method does not behave like TableView.EstimatedRowHeight, which is what I was assuming. So I ended up setting it to the auto dimension constant like this:
.BindTo<IImportedFileViewModel, ImportedFileCell>(TableView, (float)UITableView.AutomaticDimension)
I was thinking that I could just update the properties of the view models within the IObservableCollection implementation that is passed in to the BindTo method but it wasn't until I started provoking changed events on the collection itself (the collection that the view is bound to) that the cells started resizing themselves. So since I am using DynamicData as part of ReactiveUI, that meant calling SourceCache.AddOrUpdate(updatedViewModel) whenever I knew that the FailureReasonLabel had been set.
I am also going to try and restore the ReactiveUI tag that was removed from this post because I believe it to be a relevant part of this question and its answer.
I've to do a ViewController with autolayouts in scrollView, but here is few problems:
public SomeVC() : UIViewController
{
_mainScrollView = new UIScrollView {
ShowsHorizontalScrollIndicator = false,
ShowsVerticalScrollIndicator = true,
BackgroundColor = UIColor.Clear,
ScrollEnabled = true,
AutoresizingMask = UIViewAutoresizing.FlexibleHeight,
TranslatesAutoresizingMaskIntoConstraints = true
};
_userDataTableView = new UITableView(CGRect.Empty, UITableViewStyle.Grouped);
_userDataTableView.LayoutIfNeeded();
_saveButton = new UIButton();
_menuTableView = new UITableView(CGRect.Empty, UITableViewStyle.Grouped);
_menuTableView.LayoutIfNeeded();
_logoutButton = new UIButton();
}
public override void LoadView()
{
base.LoadView();
View = _mainScrollView;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Add(_userDataTableView);
Add(_saveButton);
Add(_menuTableView);
Add(_logoutButton);
_mainScrollView.AddConstraints(
_userDataTableView.AtTopOf(View),
_userDataTableView.AtLeftOf(View),
_userDataTableView.AtRightOf(View),
_userDataTableView.Height().EqualTo(_userDataTableView.ContentSize.Height),
_saveButton.Below(_userDataTableView, 20),
_saveButton.AtLeftOf(_mainScrollView, 10),
_saveButton.AtRightOf(_mainScrollView, 10),
_saveButton.Height().EqualTo(44),
_menuTableView.Below(_saveButton, 20),
_menuTableView.AtLeftOf(_mainScrollView),
_menuTableView.AtRightOf(_mainScrollView),
_menuTableView.Height().EqualTo(_menuTableView.ContentSize.Height),
_logoutButton.Below(_menuTableView, 20),
_logoutButton.AtLeftOf(_mainScrollView, 10),
_logoutButton.AtRightOf(_mainScrollView, 10),
_logoutButton.Height().EqualTo(44)
);
_mainScrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
}
In fact, it works, but contents width is about half of screen width, and scrolling not working. How to get it works?
As far as I understand, the problem is - _mainScrollView.ContentSize, but how and where should I set it, when using autolayouts?
If your views doesn't exceed the screen you will not be able to do scroll. if you only have something like this :
// Create containers
contentView = new UIView();
scrollView = new UIScrollView { contentView };
Add(scrollView);
contentView.AddSubviews(logo, user, password, loginButton);
// Auto layout
View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.AddConstraints(scrollView.FullWidthOf(View));
View.AddConstraints(scrollView.FullHeightOf(View));
View.AddConstraints(
contentView.WithSameWidth(View),
contentView.WithSameHeight(View).SetPriority(UILayoutPriority.DefaultLow)
);
scrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
scrollView.AddConstraints(contentView.FullWidthOf(scrollView));
scrollView.AddConstraints(contentView.FullHeightOf(scrollView));
// very important to make scrolling work
var bottomViewConstraint = contentView.Subviews.Last()
.AtBottomOf(contentView).Minus(20);
contentView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
contentView.AddConstraints(
logo.AtTopOf(contentView),
logo.WithRelativeWidth(contentView, 0.8f),
logo.WithSameCenterX(contentView),
logo.WithRelativeHeight(contentView, 0.3f),
user.Below(logo, 50),
user.WithRelativeWidth(logo, 0.8f),
user.WithSameCenterX(logo),
password.Below(user),
password.WithSameWidth(user),
password.WithSameCenterX(user),
loginButton.Below(password, 50),
loginButton.WithRelativeWidth(password, 0.9f),
loginButton.Height().EqualTo(50),
loginButton.WithSameCenterX(password)
);
contentView.AddConstraints(bottomViewConstraint);
}
I'm using this package and it works perfectly like if I was using a stackLayout inside a scrollview in xamarin.forms I think is the perfect behaviour.
Xamarin.IQKeyboardManager from Nuget
Also, if you want to center your content view inside the scrollview you will need to add this:
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
var scrollViewBounds = scrollView.Bounds;
var containerViewBounds = contentView.Bounds;
var scrollViewInsets = UIEdgeInsets.Zero;
scrollViewInsets.Top = scrollViewBounds.Size.Height / 2.0f;
scrollViewInsets.Top -= contentView.Bounds.Size.Height / 2.0f;
scrollViewInsets.Bottom = scrollViewBounds.Size.Height / 2.0f;
scrollViewInsets.Bottom -= contentView.Bounds.Size.Height / 2.0f;
scrollViewInsets.Bottom += 1;
scrollView.ContentInset = scrollViewInsets;
}
And thats all, doesn't matter how your contentView is . You will have a centered contetnview inside a scrollview and a manager to capture the keyboard events and adapt your view to this event .
Solution found:
Firstly:
_userDataTableView.AtLeftOf(View),
_userDataTableView.AtRightOf(View),
is not valid, instead of this, we should use:
_userDataTableView.AtLeftOf(View),
_userDataTableView.WithSameWidth(View),
if we want margin, we just add
_userDataTableView.WithSameWidth(View).Minus(MARGIN)
And the last thing we have to do:
_logoutButton.Height().EqualTo(44),
_logoutButton.Bottom().EqualTo().BottomOf(_mainScrollView).Plus(10)
last line is very important. It says to scrollView right content size.
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!
I'm trying to create a scrollView where u scroll between different labels. As an illustration i have this image:
I want to make the bottom scrollView i've tried creating a replicate, but in my case it is only adding "Book" to the scrollView and how can i make a smaller spacing between the labels. because in my code there are one label per self.view.frame.width
categoryArray = NSArray(objects: "Book", "Elektronik")
var textWidth = 0
for val in categoryArray!
{
var textLabel: UILabel = UILabel(frame: CGRectMake(0, CGFloat(textWidth), categoryScrollView!.frame.width, categoryScrollView!.frame.height))
textLabel.textAlignment = NSTextAlignment.Center
textLabel.text = val as NSString
categoryScrollView?.addSubview(textLabel)
textWidth = textWidth + Int(textLabel.frame.size.width)
if textWidth > Int(self.view.frame.width) {
categoryScrollView?.contentSize = CGSizeMake(CGFloat(textWidth), categoryScrollView!.frame.height);
}
}
I don't read swift very well, but it looks to me like the code is advancing the y position of the label frame on each iteration, rather than the x. In other words, change:
CGRectMake(0, CGFloat(textWidth), categoryScrollView!.frame.width, categoryScrollView!.frame.height)
to:
CGRectMake(CGFloat(textWidth), 0, categoryScrollView!.frame.width, categoryScrollView!.frame.height))