Update segmented control in ios without change interface - ios

when I update segmented control text, the interface (segment's width) changed and cut some letters.
[segmentedcontoll setTitle:#"test" forSegmentAtIndex:1];
segmentedcontoll.apportionsSegmentWidthsByContent = YES;
How can I solve this ?
EDIT:

It looks like your content has outgrown the dimensions of the standard UISegmentedControl.
If you are okay with smaller font, it's possible to set the entire control to have a smaller font point size, seen here.
Another option is to configure the segments the other supported way.. With images. It's a little bit of a hack, but you can create images on the fly with the UIView Snapshotting API of views/labels configured however you want and set images for each segment instead of using text. This would allow you to create 2 line labels with fixed widths and set images for each section to be images generated from the label as the content changes. More work, but you would still be using the standard class.
The last option, which might work the best for you, is to create some other custom control that does what you would like. After all, UISegmentedControl really is just a nice button container. And it does somewhat seem like you are using the control in a non-standard way - both as a control and an input form section.
Others have gone this route before and created alternatives that you can use.

You can create a separate class as below,
class CustomSegmentedControl: UISegmentedControl {
//code for creating multi line
override func didMoveToSuperview()
{
for segment in subviews
{
for subview in segment.subviews
{
if let segmentLabel = subview as? UILabel
{
segmentLabel.numberOfLines = 0 //just change here the number of lines and check it.
}
}
}
}
}
and create an outlet in your viewcontroller as,
// Initialize
let items = ["Purple", "Green", "New Segment"]
let customSC = CustomSegmentedControl(items: items)
use customSC and do what ever you want to do, similar to segmentedControl object.

Related

How to create conditional questions in a form for an ios app?

How can I dynamically add additional text fields to a view based on the response to previous question which is a drop down with set list of options.
The issue I am having is with dynamic positioning. For example if I place the field beneath but keep it hidden and show when an option is selected that only works one way. What if I select the other option how can I use the same space to show a different question/text field?
Of course I could overlay all of the options in their positions and show/hide. But is there a better way to build a dynamic form with conditional logic for questions?
Diagram:
If it were me, to make it simple for both myself and the viewer, I would have predefined space. Say, 20% of the view. Then, add questions to the scrollView variably, depending on the situation. The user can then scroll through that view.
let rect = CGRect(x: view.frame.width*0.1, y: someHeightDownInTheView, width: view.frame.width*0.8, height: view.frame.height*0.2)
let scrollView = UIScrollView(frame: rect)
let questions = ["Do I want to be a unicorn"]
if(question2.answer == "A") {
questions.append("Do I want to be a fairy princess")
}
//...Specific options
for question in questions {
let label:UILabel = createQuestion(name: "someName", question: question)
let answer:UITextView = createAnswer(name: "someName")
scrollView.addSubview(label)
scrollView.addSubview(answer)
}
func createQuestion(name: String, question: String) -> UILabel {
//Create a question with a UILabel of some SET SIZE
}
func createAnswer(name: String) -> UITextView {
//Create answer with a UITextView of some SIZE
}
There are various ways to handle variable numbers of fields.
You could create a table view or collection view, and have each cell, or each grouped set of cells, represent a question and its text field.
You could also use a vertical stack view. You can add or remove items from a stack view and it updates make room for/close up empty space as needed.
There are tons of examples of both approaches online. Which is the best fit depends on the details, but if you only ever have at most 2 questions/answers on-screen then maybe a stack view is the way to go.

Custom title view as large title in iOS 11 new navigation bar

I am using a button as a title view for my UITableViewController which opens a dropdown list of categories. Selecting a category filters content of the table view by the selected category.
The button shows the name of the selected category plus a small arrow, similar to how iBooks used to look (or maybe still looks? I haven't used it in a while). I would therefore like it to have the same behaviour as a standard title and have it be large at first and collapse when the table view is scrolled.
Is there a way to do this?
Thanks
It seems because of the new large titles, IOS11 requires the constraints on the custom view in the navigationItem.titleView to be set.
Do this for example:
customView.widthAnchor.constraint(equalToConstant: 200).isActive = true
customView.heightAnchor.constraint(equalToConstant: 44).isActive = true
self.navigationItem.titleView = customView
Note this must be done for both width and height.
It should work. No need to add a button, at least in my case...
This was suggested by Apple to ensure that you don't have zero-size custom views. See slide 33 in https://developer.apple.com/videos/play/wwdc2017/204/
Looks like touches are broken for navigationItem.titleView. Gestures, tap events and buttons - nothing works
Seems like a bug in iOS 11: https://forums.developer.apple.com/thread/82466
I provisionally implemented this workaround:
private lazy var navBarActionButtonIOS11: UIButton = {
button.addTarget(self.navTitleView, action: #selector(self.navTitleView.didTapView), for: .touchUpInside)
return button
}()
[...]
navigationItem.titleView = navTitleView
if #available(iOS 11.0, *), let navBar = navigationController?.navigationBar {
navBarActionButtonIOS11.removeFromSuperview()
navBar.addSubview(navBarActionButtonIOS11)
navBarActionButtonIOS11.center.x = navBar.center.x
}
Another solution could be to just assign a UIButton to navigationItem.titleView directly.
I hope Apple fixes this soon!
Well, I had same problem. I have UIButtons in UINavigationItem.titleView and those were not reacting to touches at all. Problem is that the view where those buttons are where of size (0,0) because of auto layout. So to fix this problem you need to add additional view into your custom view, lets call it "contentView" and put all your controls inside that contentView. Also, contentView must have defined size with constraints. Quick test is to add width and height constraint to contentView. And all works again.
Hope that this helps someone.

Change color of UILabel if UITextField (in corresponding UIView) is disabled? (Swift)

I have multiple inputs that are disabled/enabled based on certain conditions — is there a way to select the adjacent UILabel that is in the same view?
Here's a visual the UITextField/UILabel:
You can find any views in a view with a simple loop.
for view in view.subviews {
if let label = view as? UILabel {
// do something with your view
}
}
Use viewWithTag option ,give specific tag to textField and fetch them
if let theTextField = self.view.viewWithTag(1) as? UITextField {
print(theTextField.text)
}
I don't think there is a direct way of identifying the adjacent label for a field. You'd have to loop through the labels looking for one in the correct position.
Instead give your text fields tags 1-10, and give your labels corresponding tags 101-110.
Then use the tag number to find the label.

UILabel text property when set to nil or "" makes UILabel disappear from view (Swift / Autolayout/ iOS9.1)

I am going through the Stanford Winter 2015 Swift/iOS course and while doing the assignments I run into a behavior I'd like to change.
I use Autolayout as described in the videos (making the display pin to leading and trailing view edges) and the Calculator app "Display" UILabel is fine with an initial value of 0 and whenever the value used to set it (a String) is non-nil and non "".
If it is either nil or "", the entire UILabel disappears. What I am trying to do is to "clear" the display whenever there is no value to display or an incorrect calculation resulted in nil.
Any tips on who to deal with this in general? "Clearing" a UILabel without changing it's on-screen dimensions?
Edit (thanks Rob)
The UILabel has the following constraints
1. Option-click drag-left to containing UIView, selected "leading" something (on commute to work can't check yet for exact wording.
2. Same method as (1) except that the drag is to the right edge and selecting "trailing"
3. Option click-drag up to top of view, select "vertical" menu option.
4. Same as (3) except that drag is to a UIButton underneath the UILabel on the GUI.
With those settings, the label when it contains a number is always visible and (if understand, will color it to verify) stretches across the screen even if the text doesn't.
The layout looks correct in profile and landscape as long as content of UILabel is not empty. If empty, it seems to "shrink to fit" so much that the buttons below get moved up towards the top.
I'm a C++ dev since mid 90s but I have little UI experience and no more than a couple weeks experience in iOS/Swift development.
Thanks!
You can always give the UILabel a min width and min height or constraints that holds the left and right side of the label. That should keep the label from changing it's dimensions to zero.
Use a custom UILabel class assigned in Interface Builder >> Identity inspector >> Custom Class >> Class to override UILabel intrinsic content size.
No need to create any superfluous auto-layout constraints.
Swift:
class UILabelNonCompressible: UILabel
{
private static let NonCompressibleInvisibleContent = " "
override var intrinsicContentSize: CGSize
{
if /* zero-width */ text == nil ? true : text!.isEmpty
{
// prefer mirror-and-calculate over modify-calculate-restore due to KVO
let doppelganger = createCopy()
// calculate for any non-zero -height content
doppelganger.text = UILabelNonCompressible.NonCompressibleInvisibleContent
// override
return doppelganger.intrinsicContentSize
}
else
{
return super.intrinsicContentSize
}
}
}
You will also need "How do copy for UILabel?":
extension UILabel
{
func createCopy() -> UILabel
{
let archivedData = NSKeyedArchiver.archivedData(withRootObject: self)
return NSKeyedUnarchiver.unarchiveObject(with: archivedData) as! UILabel
}
}

Implement the Android Market layout in an iOS view

I'm looking for an efficient way to implement the same kind of layout that the Android market.
Right now I'm using a UITableView with custom cells. The data I'm sending from the server is something of the sort:
[
{
url: "app://url_of_content_in_the_app",
image: "http://url of the featured image",
height: 100
}
},
{
url: "app://url_of_content_in_the_app",
image: "http://url of the featured image",
height: 100
}
]
And I was thinking of updating the custom cell to support 2 or 3 buttons inside each cell, but I'm not sure this is the most efficient way to handle this. I was also thinking about a simple HTML page but I want the content to be cacheable easily.
One last point, the UITableView way only handles horizontal subdivisions such as:
_______
|__|__|
|_____|
I can't do something like:
_______
| |__|
|__|__|
You can do something like your last example (three-way cell), just have a cell two units high that you present three cells in as separate views.
Or at some point you may just decide putting views into a scroll view makes more sense, if there are not enough aspects of a UITableView you are making use of.
I would suggest putting two (or 3) custom subclasses of UIView inside the cell.
If you want them be be user interact-able - add your own UIGestureRecognizer to the view.
NSRect b = cell.contentView.bounds;
UIView *a = [[MyView alloc] initWithFrame:NSRectMake(NSRectGetMinX(b),NSRectGetMinY(b), NSRectGetWidth(b)/2., NSRectGetHeight(b))];
UIView *b; //... similarly
// set auto resize mask for a/b appropriately
[cell.contentView addSubview:a];
[cell.contentView addSubview:b];
(not checked for typos)
having a custom cell with that initialization code within it is a good idea

Resources