I have uicollectionview and each cell has a SelectedBackgroundView property with just the background colour like this:
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
How would I set the width of the selectedbackgroundview? I need it to be half the default value.
I have tried:
SelectedBackgroundView.Frame = new CGRect(SelectedBackgroundView.Frame.X, SelectedBackgroundView.Frame.Y, SelectedBackgroundView.Frame.Width / 2, SelectedBackgroundView.Frame.Height / 2);
But this just distorts the view
This where I put the code:
[Export ("initWithFrame:")]
public PhotoCell(CGRect frame) : base(frame)
{
//BackgroundView = new UIView { BackgroundColor = UIColor.Clear };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
this.AddConstraint(NSLayoutConstraint.Create(this.SelectedBackgroundView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, this.Bounds.Height / 2));
imageView = new UIImageView(frame); // set as you want
ContentView.AddSubview(imageView);
}
Why not add constraints?
You can specify the width and height constraints as NSLayoutConstraints and then add them to your UICollectionViewCell using the AddConstraint method. Here's an example in F#:
myCell.AddConstraint(NSLayoutConstraint.Create(SelectedBackgroundView, NSLayoutAttribute.Height, NSLayoutRelation.Equal,null,NSLayoutAttribute.NoAttribute, 1, myHeightValue))
It would be very similar, if not identical in C#
This code solved my problem:
SelectedBackgroundView.Frame = new CGRect(SelectedBackgroundView.Frame.X + 5, SelectedBackgroundView.Frame.Y + 5, SelectedBackgroundView.Frame.Width-10, SelectedBackgroundView.Frame.Height-10);
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 have ViewContoller, and it is view hierarchy is the following (Cirrious.FluentLayout Library, but It should be understandable):
_scrollView = new UIScrollView()
{
ShowsVerticalScrollIndicator = false
};
View.Add(_scrollView);
_contentView = new UIView();
_scrollView.Add(_contentView);
View.AddConstraints(
_scrollView.Below(VueNavBar),
_scrollView.AtLeftOf(View),
_scrollView.AtRightOf(View),
_scrollView.AtBottomOf(View)
);
_scrollView.AddConstraints(_contentView.SameFrameAs(_scrollView));
Then I add UISwitch in the following way:
var switch = new UISwitch();
_contentView.Add(switch);
After setting up constraints (I have tried many sets of constraints, many of them are definitely not ambiguous) iOS renders me the following:
It is really weird, but after toggling it changes to:
Maybe someone have any ideas why it happens?
P.S.: I have managed to broke switches on other pages by adding scroll view in the same way, however they have been broken in a differently (Other type of glitch).
I tried the code below and the switch displayed normally.
And there is no need for you to define the width and height of a UISwitch.
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
_scrollView = new UIScrollView()
{
ShowsVerticalScrollIndicator = false,
BackgroundColor = UIColor.Blue
};
View.Add(_scrollView);
this.View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.AddConstraints(
_scrollView.AtTopOf(View,20),
_scrollView.AtLeftOf(View,20),
_scrollView.AtRightOf(View, 20),
_scrollView.AtBottomOf(View, 20)
);
_contentView = new UIView();
_contentView.BackgroundColor = UIColor.Orange;
_scrollView.Add(_contentView);
_scrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
_scrollView.AddConstraints(
_contentView.WithSameTop(_scrollView),
_contentView.WithSameLeft(_scrollView),
_contentView.WithSameWidth(_scrollView),
_contentView.WithSameHeight(_scrollView)
);
var switch1 = new UISwitch();
_contentView.Add(switch1);
_contentView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
_contentView.AddConstraints(
switch1.AtTopOf(_contentView, 80),
switch1.AtLeftOf(_contentView, 20)
);
}
I add UIViews dynamically in code. There are a lot of views I want to add. Here is one for example:
let typeImage = UIImageView()
typeImage.translatesAutoresizingMaskIntoConstraints = false
rootView.addSubview(typeImage)
typeImage.widthAnchor.constraint(equalToConstant: 28).isActive = true
typeImage.heightAnchor.constraint(equalToConstant: 28).isActive = true
typeImage.leftAnchor.constraint(equalTo: rootView.leftAnchor, constant: 4).isActive = true
typeImage.topAnchor.constraint(equalTo: rootView.topAnchor, constant: 4).isActive = true
typeImage.backgroundColor = gh.myRed
typeImage.image = UIImage(named: "ic_question_bej")
I want to count sum of all elements that I add and finally set this counted value to my root view height. The problem is that
typeImage.frame.size.height
typeImage.bounds.size.height
always return 0.0
So how can I get height in CGFloat of newly added UIView via code?
Maybe I should set height of rootview to wrap all my subview in another way?
Edit
Xcode loads view with some delay and if you will try to get view size immediately after adding it to parent you will get 0.0 sizes.
You have to call yourCustomView.layoutIfNeeded() before cheking sizes.
Thanks Chenjtc for right Answer.
you can add the code like this:
typeImage.layoutIfNeeded()
before the code :
typeImage.frame.size.height
typeImage.bounds.size.height
constraint will not layout immediately, you should use layoutIfNeeded to layout the view, then you can get th frame
If you want the sum of multiple views height in CGFloat you can do it like this :
let viewHeight = self.view.frame.height //this in CGFloat
let sumHeight = viewHeight + ... other UIViews
print(sumHeight) // 568.0 for iPhone SE
or if you want to set your new UIView height you can do it by changing :
typeImage.heightAnchor.constraint(equalToConstant: 28).isActive = true
//
To :
typeImage.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1).isActive = true
UPDATE
Now Solved The problem was that when I was updating the bottomConstraint I was setting the Constant to the bottom padding property. Sounds reasonable but of course the Constant should have been set to 0 - BottomPadding. That explains why the bottom of the text was being not visible, it was being constrained beyond its clipping container.
I have a simple UIView custom control called PaddedLabel that wraps (not inherits) a UILabel
The view hierarchy is
PaddedLabel -> UILabel
When the constraints on the UILabel have their constants updated the outer View does not chnage height. It is as if the outer UIView is seeing only the Height of the Label as the Height it needs rather than the Height of the Label plus constants. This is how it looks
In UpdateConstraints I add some constraints and if there is a Text value I set the Constant on the Constraint to the value I want for padding else I set the Constant to 0.
public override void UpdateConstraints()
{
base.UpdateConstraints();
if (this.constraintsApplied == false)
{
this.leftConstraint =
NSLayoutConstraint.Create(this.NestedLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1.0f, this.LeftPadding);
this.AddConstraint(this.leftConstraint);
this.rightConstraint =
NSLayoutConstraint.Create(this.NestedLabel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this, NSLayoutAttribute.Right, 1.0f, 0 - this.RightPadding);
this.AddConstraint(this.rightConstraint);
this.topConstraint =
NSLayoutConstraint.Create(this.NestedLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1.0f, this.TopPadding);
this.AddConstraint(this.topConstraint);
this.bottomConstraint =
NSLayoutConstraint.Create(this.NestedLabel, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1.0f, 0 - this.BottomPadding);
this.AddConstraint(this.bottomConstraint);
this.constraintsApplied = true;
}
if (this.Text.HasValue())
{
this.topConstraint.Constant = this.TopPadding;
// The following code was the problem.
// It should have been 0 - this.BottomPadding Now corrected
// this.bottomConstraint.Constant = this.BottomPadding;</del>
this.bottomConstraint.Constant = 0 - this.BottomPadding;
}
else
{
this.topConstraint.Constant = 0;
this.bottomConstraint.Constant = 0;
}
}
When the Text property is set I set the Text property on the inner UILabel and call SetNeedsUpdateConstraints
public string Text
{
get
{
return this.text;
}
set
{
if (this.text == value)
{
return;
}
this.text = value;
this.nestedLabel.Text = value;
this.SetNeedsUpdateConstraints();
}
}
If you want the PaddedLabel view to expand and fit around the inside UILabel, change the bottom constraint. You want to tie the bottom of PaddedLabel to the bottom of the UILabel, so as the UILabel grows it makes PaddedLabel expand! The way it is now, you're telling the UILabel to squish itself inside of the PaddedLabel view.
Reverse the bottomConstraint and you should be set.
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.