Resizing a UITextView programmatically in Swift 2 to enlarge its width - uitableview

EDIT: I post a screenshot of what I would like to implement in iPad and iPhone. When using the button in iPhone, the UITableView opens and has to cover a part of the UITextView.
I have a universal project for iPhone and iPad. In the main storyboard there are two controls, an UITextField and a UITableView. The UITextField keeps the left 1/3 portion of the screen and the UITableView the remaining part of the screen.
When in iPhone, I hide the UITableView and I would like that the UITextView keeps all the screen. Then, when the user taps on a button, the UITableView appears over the text field (I dismiss the UITableView as soon as the user selects a choice).
How can I have the tableView to enlarge in a way that its right border, go to the right border of the screen?

One way to implement what you described is to start with the TableView "outside" of the scene, with a negative Leading Space to the main view. Them when users press the button, the value of the Leading Space Constraint is set to zero.
Example:
Final result:
ViewController code:
class ViewController: UIViewController {
#IBOutlet weak var tableViewLeadingMargin: NSLayoutConstraint!
#IBAction func revealTableView(sender: UIButton) {
UIView.animateWithDuration(
3.0,
animations: {
self.tableViewLeadingMargin.constant = 0
self.view.layoutIfNeeded()
}
)
}
}
There's just one caveat: you'll need to adjust the width of the TableView programatically, based on the iPhone screen size.
The answer above the iPhone issue. For iPad, I'd suggest using Size Classes, creating a specific layout/constraints for them:
To illustrate:

Related

How do I expand and collapse a UICollectionViewCell with swift?

The Collection view cell would need to show and hide additional tools for the device being controlled. The button that collapses would be at the bottom of the UICollectionViewCell. Whenever the button is pressed it would animate downwards revealing the fan or lights extra features or animate upwards when hiding the extra features. I only need help with expanding and collapsing by using the button at the bottom of the cell. An image is attached showing an example.
Add a height constraint for your high/med/low selector.
Connect that constraint to var in your cell class like this:
#IBOutlet weak var checker1HeightConstraint: NSLayoutConstraint!
set that constraint to a value you want (either 0, for hidden, or 50 or 60 if not hidden)
have a method where you set the value:
func toggleControls(visible: Bool)) {
checker1HeightConstraint = visible? 50 : 0
setNeedsLayout()
}
If you are not sure how to set the outlet, just ctrl-drag from the constraint in you storyboard or xib to your custom cellView class. It will give you options to create it.

Keep Bottom of TableView Visible When Keyboard Shows With Autolayout in Swift

I have a tableview with a textview for entering text immediately below it similar to Apple Messages. When the user begins to enter text and the keyboard appears, I want the following behavior similar to IOS Messages.
If the keyboard will not cover anything, the visible part of the tableview remains unchanged.
If the keyboard will cover something, the tableview moves up just enough so that its bottom-most filled cell is just above the keyboard.
Because I'm using autolayout, I currently have a constraint between the tableview and the textview below it. Also, the project has IQKeyboard which manages a lot of other views involving textfields and textviews.
The constraint combined with IQKeyboard accomplishes 2. When the keyboard appears, the keyboard pushes the textview up. The textview pushes the tableview up. So if the tableview is fully populated, you see the last cell of the tableview above the textview above the keyboard as desired.
However, 2. is not working.
if the tableview is not filled, the keyboard pushes up the textview which pushes up the tableview so that you longer see the top of the tableview.
I have tried adjusting the contentOffset property of the tableview when the Keyboard Shows and this sort of works but the tableview initially moves up before coming back down. I think this is because the notification to change the offset property does not fire until after the keyboard has begun to move up.
I also tried adjusting the tableview height to its content but this causes the textview to expand to fill the difference due to constraints.
Content offset approach - problem is that content offset adjusts too late
//register for keyboard notifications and in handler:
if let infoKey = notification.userInfo?[UIKeyboardFrameEndUserInfoKey],
let rawFrame = (infoKey as AnyObject).cgRectValue {
let keyboardFrame = view.convert(rawFrame, from: nil)
self.heightKeyboard = keyboardFrame.size.height
UIView.animate(withDuration: 0.2, animations: {
self.tableView.contentInset = UIEdgeInsetsMake(self.heightKeyboard!, 0, 0, 0);
})
}
Can anyone suggest a way to mimic the behavior of Apple Messages? Thanks in advance for any suggestions.
One approach:
constrain the top of the tableView to the top of the view
constrain the bottom of the tableView to the top of the textField
constrain the bottom of the textField to the bottom of the view
create an #IBOutlet for the textField's bottom constraint
When the keyboard is shown, change the .constant of the textField's bottom constraint to the height of the keyboard view.
This will move the textField up, and because it's top is constrained to the bottom of the tableView, it will also move the tableView's bottom edge up.
Then scroll to the bottom of the tableView.
Layout:
Initial hierarchy, with 20 rows (scrolled to the bottom):
Hierarchy view (tableView background color set to green, so we can see its frame):
View after the keyboard is shown:
Hierarchy after the keyboard is shown:
Little tough to see from static screen caps, but the frame of the green rectangle (the tableView background) is now shorter... the user can still scroll up and down to see all the rows, but the bottom of the tableView is still constrained to the top of the textField.
When you the keyboard is dismissed, set the .constant of the textField's bottom constraint back to Zero.
You can see a full, working example project up on GitHub: https://github.com/DonMag/KBAdjust

How to autoscale UIButton and title text correctly?

I'm trying to make buttons with titles that would change their width, height and font size of the title text depending on iOS device (autoscaling). I'm using Xcode 10 coding Swift.
Here is the simple example: I created in IB red button that covers the whole screen (top, bottom, leading and trailing constraints are set to 0) with the title "Button" in the center with the font size set to 350. The title would fit width of 12.9" iPad perfectly (see the pic).
I entered FitToWidth code like this:
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.minimumScaleFactor = 0.1
}
When I run the code on device with lower screen resolution than iPad 12.9" I see that the button title is scaled and fits the screen width but it is shifted down (see the pics).
iPad 12.9 simulation
iPhone SE simulation
What am I missing?
I need title text to be situated in the center of the button as I did it in IB. I tried various constraints applied to the button but nothing worked out.
It looks like I found a solution.
I just added such string to my code in viewDidLoad:
button.titleLabel?.baselineAdjustment = UIBaselineAdjustment.alignCenters
Now the title is in the middle of the button for any iOS device:
Resize the button view to make title fit in each screen size
Try this in viewDidAppear()
button.sizeToFit()

UIView constraint behaving differently when using iPhone X

I have a viewcontroller with a UITableView that takes up the majority of the screen. At the bottom of the viewcontroller, I have a UIView called controlView with some buttons. When the viewcontroller first loads, I set the NSLayoutConstraint that manages the height of controlView to 1 so that controlView is not visible.
#IBOutlet weak var controlViewHeightConstraint: NSLayoutConstraint!
controlViewHeightConstraint.constant = 1.0
When a user taps on a tableview cell, I adjust controlViewHeightConstraint.constant to make it visible
controlViewHeightConstraint.constant = heightConstant //heightConstant = 65
self.view.layoutIfNeeded()
This has been working perfectly for the iphone 5, 6, 7, 8, and 8+. However, with the X, when I call controlViewHeightConstraint=1 in viewDidLoad, the controlView is still visible. Any idea why it is appearing when it should not be visible.
storyboard setup
iPhone 8+ before tapping cell
iPhone 8+ after tapping cell
iPhone X before tapping cell
iPhone X after tapping cell
Solved this issue by adjusting the top constraint of the controlView to be below the screen by default and adjusting the constraint to move the view up to become visible. For some reason adjusting the height constraint of the view would not work with the iPhone X. Might be due to complications with the bottom safe area portion of the iPhone X.

UIScrollView weird behavior with UITextField/UIPickerView

So I'm pretty puzzled right now because my UIScrollView is acting pretty weirdly.
Basically, I have a UIScrollView that is about twice the height of an iPhone 6 that I am using to display some graphs using iOS Charts and so I've set it to be able to scroll and bounce vertically, but neither scroll nor bounce horizontally. All of the graphs, and some additional UITextFields and UILabels are embedded on a separate "body view" that is aligned with the frame of the UIScrollView as seems to be common practice. Thus, the hierarchy of my views looks like this:
This worked well until I noticed today that when I press a specific UITextField on this UIScrollView, which triggers a UIPickerView, all of the sudden my scroll view starts to allow horizontal bouncing. This behavior does not occur for the two other UITextField's on the body view when they are tapped.
I've checked all of the code that is being triggered by tapping on the affected text field, and nothing is directly editing the frames or bounds of any UI objects. In fact, the only function called when the text field is tapped on is the textFieldDidBeginEditing. I've attached the code for this function below, but I am fairly certain it is not the problem.
My next suspicion was that the UIPickerView popping up has been messing with the dimensions of my scroll view and/or it's embedded view. I'm not quite sure if this is possible/probable, but this whole thing has left me pretty stumped.
Here's my code:
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == overallTimeframeTextField {
...
// Not the problematic text field
} else if textField == subjectTimeframeTextField {
...
// Also not the problematic text field
} else { // Affected text field
// Set the text of the text field
if textField.text == "" {
// This is executed in this scenario
textField.text = subjectPickerData[0]
} else {
...
}
}
}
Here is a short GIF outlining my issue. You can see me scrolling down the page, where I am not able to bounce horizontally, and then once I tag on the text field, all of the sudden the scroll view allows the bounces.
GIF
I'm pretty lost with this issue, so any help would be appreciated.
Edit
To clarify, I explicitly declare my scrollView's content size to be equal the desired height and the width of the screen that the user is on. I then set the bodyView's width to equal the same value. This is done in viewDidAppear with the following code:
// Fit the content to the screen
scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: 1200)
bodyView.frame.size.width = UIScreen.main.bounds.width
I also have constraints which force the scrollview and body view to both have the same width as the UIViewController's default child view (the parent of the scroll view in my hierarchy).
One interesting thing that I've noticed is that when I print the width of my scroll view and my body view when the views load, I receive the following output for iPhone 6:
385.0
385.0
This is correct as that is the width of an iPhone 6. However, when I tap on the text field, and then print the same values, I get this output:
385.0
384.0
So for some reason, my body view is one point smaller than my scroll view. I've tried setting the body view's width to be equal to the scroll view when I tap on the text field, like I do in the viewDidAppear function, but this had no effect.
In terms of the UIPickerView, I initialize a pickerview with my class instance variables like so:
var subjectPickerView = UIPickerView()
I then assign this picker view to be the input view for the text field in viewDidLoad:
textField.inputView = subjectPickerView
So I'm not sure if this makes the picker view a subview of the scroll view, but it's just replacing the keyboard in this scenario.
Thanks to #AchmadJP's comment, I tried explicitly creating an equal widths constraint between my scroll view and my body view. This seems to have solved the issue.
The reason I had not done this previously was that the body view's leading space, trailing space, top space and bottom space were constrained to be the same as those of the scroll view. Theoretically, this should have meant that the widths were equal at all times, but apparently, that is not the case.
For anyone else with the same problem, you can see this answer for the solution.

Resources