In my xamarin iOS app I have a list view, I want to show the loading icon when it is being loading. But, I do not want to disable the whole page. I want the user to still go back if they wish to, using back navigation.
I used this as a reference.
So, I'm trying to set the CGRect Frame, to leave the navigation on the top active and disable the rest of the page during loading status.
I am using something like this: new CGRect(30, 0,0, 0) to leave 30 units from the top but it doesnt work. Can anyone help me out to have a frame to leave just navigation bar and cover rest of the page?
AutoLayout is a much better way to accomplish this task than using frames. Unless you need to target REALLY, REALLY old versions of iOS, AutoLayout is generally the way to go.
I'm assuming you are using a UIViewController and not a UITableViewController. This is an important distinction, because the UITableViewController only allows you to add to the UITableView which makes this task much more challenging.
Add this AddAnOverlay method to your UIViewController class, then call it whenever you want to display an overlay. You will probably need to put overlay in an instance variable so that you can remove it later. Remove it by calling overlay.RemoveFromSuperview() and you're done.
void AddAnOverlay()
{
var overlay = new UIView();
overlay.BackgroundColor = UIColor.Black.ColorWithAlpha(0.45f); // or whatever colo
overlay.TranslatesAutoresizingMaskIntoConstraints = false;
var label = new UILabel();
label.TranslatesAutoresizingMaskIntoConstraints = false;
label.Text = "Loading Fantastic Things!";
var spinner = new UIActivityIndicatorView();
spinner.TranslatesAutoresizingMaskIntoConstraints = false;
spinner.StartAnimating();
overlay.AddSubview(spinner);
overlay.AddConstraint(NSLayoutConstraint.Create(overlay, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, spinner, NSLayoutAttribute.CenterX, 1, 0));
overlay.AddConstraint(NSLayoutConstraint.Create(overlay, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, spinner, NSLayoutAttribute.CenterY, 1, 0));
overlay.AddSubview(label);
// can adjust space between by changing -30 to whatever
overlay.AddConstraint(NSLayoutConstraint.Create(spinner, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, label, NSLayoutAttribute.Top, 1, -30));
overlay.AddConstraint(NSLayoutConstraint.Create(overlay, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, label, NSLayoutAttribute.CenterX, 1, 0));
View.AddSubview(overlay);
View.AddConstraint(NSLayoutConstraint.Create(TopLayoutGuide, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, overlay, NSLayoutAttribute.Top, 1, 0));
View.AddConstraint(NSLayoutConstraint.Create(View, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, overlay, NSLayoutAttribute.CenterX, 1, 0));
View.AddConstraint(NSLayoutConstraint.Create(View, NSLayoutAttribute.Width, NSLayoutRelation.Equal, overlay, NSLayoutAttribute.Width, 1, 0));
View.AddConstraint(NSLayoutConstraint.Create(BottomLayoutGuide, NSLayoutAttribute.Top, NSLayoutRelation.Equal, overlay, NSLayoutAttribute.Bottom, 1, 0));
}
Notice the TopLayoutGuide and BottomLayoutGuide in the NSLayoutConstraint. These represent the top and bottom of your current view controller, so they can be used to size things so they don't hide navigation bars, tab bars, etc.
You have to add the overlay to the table view, which leads you to a centering problem. For this there are some options: recalculate the position of the overlay when scrolling, add an additional layer behind the table view which you reference with autolayout for positioning, ...
I'm using autolayout and you should avoid giving actual numbers, but it is also possible using bounds. Also be aware of if the user navigates away you have to cancel the task!
Related
i have one view.xib file and it's having small container(container view) which holds all the controls like button/textfield, all the events of controls is handle by parent view.xib class file.
My requirement is at one place i need to add/show parent i.e view.xib completed screen. At one more place i need to add only container view. when i add/show container view only, control's associated events/methods doesn't works.
So i thought, if i can change class of container view with parent view.xib's class, my work can be done.
so either suggest me some other solutions or class swizzaling if it's possible to handle in this way.
basically i am adding container view on uitableview cell's container(view) my code for same is as below
if let questionContainerView = cellQuestionView.viewQuestionContainer {
// let questionContainerView = cellQuestionView
cell.viewQuestionContainer.addSubview(questionContainerView)
questionContainerView.translatesAutoresizingMaskIntoConstraints = false
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.left, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.right, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.right, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0))
cell.viewQuestionContainer.addConstraint(NSLayoutConstraint(item: questionContainerView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: cell.viewQuestionContainer, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0))
cellQuestionView.layoutIfNeeded()
}
I believe what you are trying to do is create a re-usable UIView with your control buttons, that you can use in different view controllers. There is a great tutorial on Youtube entitled iOS Basically: Reusable UIView - Programming in Swift (Part 1).
Basically, you will want to create a .Xib file dedicated to the view that you want to re-use, with all the actions handled by that custom view class. Every time you will want your custom view, you will need to instantiate it from the Xib file and manually add it as a subview onto the container view.
Good luck and happy coding!
-- edit --
Your updated code shows that this will be part of a UITableView and you are trying to add your custom view on top of a UITableViewCell. You should instead instantiate a custom UITableViewCell and register it as reusable with the table view. This tutorial should guide you on doing just that: Custom UITableViewCell Tutorial - TableView with Images and Text in Swift
You can define your #IBAction in your custom table cell, and attach your button selectors to your action in your custom cell's nib.
Cheers!
I am new to iOS UI development. and i am stuck in the below issue.
I am trying to give half of the width of parent view to 2 child views. (See image). I can't set multiplier to less than zero. Both red and green child view should be equal in width, and width should be half of the parent view.
I am using visual studio for development.
You should be able to set the Multiplier to 1:2 as it works with ratios.
I feel this is a bug in the iOS designer in Visual Studio as the Multiplier is a floating point number. from the docs here:
Multiplier: The value of attribute 2 is multiplied by this floating point number. In this case, the multiplier is 1.0.
In Xamarin Studio, iOS Designer a ratio is accepted, Also 1/2 0.5:
And In Xcode:
It even gets added to the source of the xib/storyboard like so:
<constraint id="9" firstItem="3" firstAttribute="width" secondItem="8bC-Xf-vdC" secondAttribute="width" multiplier="1:2"/>
so as a work around you could edit the .xib or .storyboard file, but thats not ideal.
An alternative to setting the multiplier you could set:
RedView
LeadingSpace to superview.leadingspace
TrailingSpace to superview.CenterX
GreenView
LeadingSpace to superview.CenterX
TrailingSpace to superview.trailingspace
This will do the same as setting the width to half the the width size of the superview.
TBH Visual studio's and Xamarin studio's iOS Designers are not very good in comparision to Xcode for adding complicated constraints (this is not that complicated but it still fails). I would suggest trying to edit it in Xcode, if you can.
Update
If you want to add them programatically, add this in ViewDidLoad:
public override void ViewDidLoad()
{
base.ViewDidLoad();
greenView.TranslatesAutoresizingMaskIntoConstraints = false;
redView.TranslatesAutoresizingMaskIntoConstraints = false;
View.AddConstraints(new NSLayoutConstraint[]{
NSLayoutConstraint.Create(redView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, View, NSLayoutAttribute.Leading, 1, 0),
NSLayoutConstraint.Create(redView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1, 0),
NSLayoutConstraint.Create(redView, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1, 0),
NSLayoutConstraint.Create(greenView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, View, NSLayoutAttribute.CenterX, 1, 0),
NSLayoutConstraint.Create(greenView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, View, NSLayoutAttribute.Trailing, 1, 0),
NSLayoutConstraint.Create(greenView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, redView, NSLayoutAttribute.Top, 1, 0),
});
}
It will make a view like so:
I need to add labels one after another vertically and their number is dynamic. For now it works fine with this code:
let numUnitsLabel = UILabel(frame: CGRectZero)
numUnitsLabel.text = units
numUnitsLabel.font = UIFont.boldSystemFontOfSize(28)
numUnitsLabel.textColor = UIColor.redColor()
numUnitsLabel.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(numUnitsLabel)
let topConstraint = NSLayoutConstraint(item: numUnitsLabel, attribute: .Top, relatedBy: .Equal, toItem: cell.contentView, attribute: .Top, multiplier: 1, constant: 8 * CGFloat(i+1) + CGFloat(i*25) + CGFloat(i*20) - 5)
let rightConstraint = NSLayoutConstraint(item: numUnitsLabel, attribute: .Trailing, relatedBy: .Equal, toItem: cell.contentView, attribute: .Trailing, multiplier: 1, constant: -10)
cell.contentView.addConstraints([topConstraint, rightConstraint])
The cell is drawn fine. But when I add new item in the list and call tableView.reloadData the old labels are "remembered" and they are over new ones. The newly added object is put in the first place in the array and they are like one over another... Maybe my approach is bad, but if you have any suggestions please advice me.
Remember that cells are re-used, so however a cell was prepared previously, it still has all of that state. In particular, its view hierarchy (added subviews) remain. The reason for this is generally a layout of a Table Cell stays the same, and only its content is meant to be re-set in cellForRowAtIndexPath.
You're using an anti-pattern, first of all, which is why you're running into difficulty.
If you really want to clear out and re-layout the cell, remove all subviews explicitly, every time, e.g.:
https://techfuzionwithsam.wordpress.com/2014/12/23/what-is-the-best-way-to-remove-all-subviews-from-parent-viewsuper-view/
I suspect though, (admittedly this isn't CodeReview) that your design is flawed. Generally table cells don't need to grow in height with dynamic count of internal elements. You may need nested tables (!!), really just a single multi-line UITextView in each, or a table structured by sections with custom section header views.
If there are multiple UILabels in one UIStoryboard, and they have the same centerY, which means they are at the same line. How can I use autolayout to let them fit in different screen? I hope these UILabels have same font size.
You need to add constraints. There are a couple of ways to add constraints.
If you go to the storyboard you will see a rectangle in between 2 vertical lines. If you click the the view you want to add constraints too (Like the UIView you added) and click that rectangle box thing It gives you options to add constants to the left, right, top, bottom of the view. If you click on the dropdown menu it gives you a list of views around the view your adding constraints too so that you can add constraints relative to that view.
Another way to add constraints is clicking the triangle button in between 2 vertical lines and selecting the option "add missing constraints". Auto layout will then try and determine the best constraints to add automatically.
To delete or modify constraints you can click the "show size inspector" (looks like a ruler) and in the constraints section you should see some constraints if you have added any. You can click and delete them or edit them.
Another option is adding constraints programmatically (below is an example of adding constraints to an image view in a stack view in swift):
let trailingConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self.stackView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: -5)
let leadingConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.stackView, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 5)
self.stackView.addArrangedSubview(imageView)
self.stackView.addConstraint(trailingConstraint)
self.stackView.addConstraint(leadingConstraint)
I want to show an alert controller of style action sheet to display the list of states in a country and that works fine.
But for some weird reason it shows action sheet below status bar partially which is not acceptable as it looks bad, how ever I can remove the status bar when displaying the action sheet which should work.
So I was just wondering is there any other way to make the action sheet stop to a particular offset from the top. I tried presenting the action sheet from the navigation controller but nothing changed.
Any comments appreciated.
Thanks,
Robin.
Try this:
var height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 300)
alertController.view.addConstraint(height);
Set it height to 300. Look, will it do any changes?