2 UIView.size.height don't work? - swift

There is 2 UIView control.
#IBOutlet weak var vw: UIView!;
#IBOutlet weak var lbl: UILabel!;
I want to set height = 0.0;
Like this...
vw.frame.size.height = 0.0;
lbl.frame.size.height = 0.0;
And
I do this !
override func viewWillAppear( animated: Bool )
{
vw.frame.size.height = 0.0;
lbl.frame.size.height = 0.0;
}
override func viewDidAppear( animated: Bool )
{
vw.frame.size.height = 0.0;
lbl.frame.size.height = 0.0;
}
But It's don't work !!!
How can I solved the problem ?
Why don't work ? Is script ?
It's very different to MicroSoft Control.
Thanks in advance ^^;;;

Assuming your code isn't crashing because the vw object is nil. Then its probably a problem with auto layout.
You have them as #IBOutlets, are the views created in a storyboard?
If so, are you using auto layout? If you are, you need to set the constant of the constraint for their height. Create an outlet to the constraint and connect it in storyboard to it (the same way you did the views).
#IBOutlet weak var viewHeightConstraint: NSLayoutConstraint?
override func viewWillAppear( animated: Bool ) {
vwHeightConstraint.constant = 0
}
Your constraints still exist, so even when you set the frame height, the auto layout constraint just sets it back to the height defined in the storyboard.

Related

Swift - scrollViewDidScroll not working with WKWebView

I'm trying to add a shadow to my (custom) nav bar when a user scrolls using scrollViewDidScroll but it doesn't do anything. I have the same exact code on another view controller but it has a tableView instead of a WKWebView and it works fine.
I tried adding webView.scrollView.delegate = self but I just get an error.
My code:
class ViewController: UIViewController {
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var navBar: UIView!
override func viewDidLoad() {
super.viewDidLoad()
addShadow()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let navigationBar = navBar
let offset = scrollView.contentOffset.y / 10
if offset > 1.5 {
navigationBar?.layer.shadowOpacity = 0.15
} else {
navigationBar?.layer.shadowOpacity = Float(((3 * offset) / 20)/1.5)
}
}
func addShadow() {
navBar.layer.shadowColor = UIColor.black.cgColor
navBar.layer.shadowOffset = CGSize(width: 0, height: 2.0)
navBar.layer.shadowRadius = 6.0
navBar.layer.masksToBounds = false
}
}
I tried adding webView.scrollView.delegate = self but I just get an error.
You didn't share what the error was. I suspect though that you didn't declare your view controller as UIScrollViewDelegate conforming, which caused the compile time error when trying to set self as the scroll view delegate.
Change your view controller declaration to this:
class ViewController: UIViewController, UIScrollViewDelegate {

How to update the constant height constraint of a UIView programmatically?

I have a UIView and I set the constraints using Xcode Interface Builder.
Now I need to update that UIView instance's height constant programmatically.
There is a function that goes like myUIView.updateConstraints(), but I don't know how to use it.
Select the height constraint from the Interface builder and take an outlet of it. So, when you want to change the height of the view you can use the below code.
yourHeightConstraintOutlet.constant = someValue
yourView.layoutIfNeeded()
Method updateConstraints() is an instance method of UIView. It is helpful when you are setting the constraints programmatically. It updates constraints for the view. For more detail click here.
If you have a view with multiple constrains, a much easier way without having to create multiple outlets would be:
In interface builder, give each constraint you wish to modify an identifier:
Then in code you can modify multiple constraints like so:
for constraint in self.view.constraints {
if constraint.identifier == "myConstraint" {
constraint.constant = 50
}
}
myView.layoutIfNeeded()
You can give multiple constrains the same identifier thus allowing you to group together constrains and modify all at once.
Change HeightConstraint and WidthConstraint Without creating IBOutlet.
Note: Assign height or width constraint in Storyboard or XIB file. after fetching this Constraint using this extension.
You can use this extension to fetch a height and width Constraint:
extension UIView {
var heightConstraint: NSLayoutConstraint? {
get {
return constraints.first(where: {
$0.firstAttribute == .height && $0.relation == .equal
})
}
set { setNeedsLayout() }
}
var widthConstraint: NSLayoutConstraint? {
get {
return constraints.first(where: {
$0.firstAttribute == .width && $0.relation == .equal
})
}
set { setNeedsLayout() }
}
}
You can use:
yourView.heightConstraint?.constant = newValue
Drag the constraint into your VC as an IBOutlet. Then you can change its associated value (and other properties; check the documentation):
#IBOutlet myConstraint : NSLayoutConstraint!
#IBOutlet myView : UIView!
func updateConstraints() {
// You should handle UI updates on the main queue, whenever possible
DispatchQueue.main.async {
self.myConstraint.constant = 10
self.myView.layoutIfNeeded()
}
}
You can update your constraint with a smooth animation if you want, see the chunk of code below:
heightOrWidthConstraint.constant = 100
UIView.animate(withDuration: animateTime, animations:{
self.view.layoutIfNeeded()
})
To update a layout constraint you only need to update the constant property and call layoutIfNeeded after.
myConstraint.constant = newValue
myView.layoutIfNeeded()
If the above method does not work then make sure you update it in Dispatch.main.async{} block. You do not need to call layoutIfNeeded() method then.
First connect the Height constraint in to our viewcontroller for creating IBOutlet like the below code shown
#IBOutlet weak var select_dateHeight: NSLayoutConstraint!
then put the below code in view did load or inside any actions
self.select_dateHeight.constant = 0 // we can change the height value
if it is inside a button click
#IBAction func Feedback_button(_ sender: Any) {
self.select_dateHeight.constant = 0
}
Create an IBOutlet of NSLayoutConstraint of yourView and update the constant value accordingly the condition specifies.
//Connect them from Interface
#IBOutlet viewHeight: NSLayoutConstraint!
#IBOutlet view: UIView!
private func updateViewHeight(height:Int){
guard let aView = view, aViewHeight = viewHeight else{
return
}
aViewHeight.constant = height
aView.layoutIfNeeded()
}
If you update your constraints with animation then add layout subview in UIView.animate...
for example,
#IBOutlet viewHeight: NSLayoutConstraint!
#IBOutlet view: UIView!
private func updateViewHeight(height:Int){
guard let aView = view, aViewHeight = viewHeight else{
return
}
aViewHeight.constant = height
UIView.animateWithDuration(0.5, delay: 0) { [self] in
aView.layoutIfNeeded()
}
}

Detect TextView Scrolling to Show a Button in Swift 3.0

I have a TextView and a hidden button within a UIView, and I'm trying to detect when the user scrolls down to the bottom of a long list of text and to show the hidden button when they reach the bottom. I saw some old posts on how it was done in Obj-C using scrollViewDidScroll, but not really sure how to do that with swift, or how to do it with a TextView instead of a ScrollView. Any help would be great as I haven't gone very far with this one.
So far this is my attempt at translating the obj-c post to swift, but it hasn't worked for me, in fact I'm not even sure when the function is called:
import UIKit
class MainVC: UIViewController, UIScrollViewDelegate {
#IBOutlet var textView: UIScrollView!
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
}
func scrollViewDidScroll(textV: UIScrollView) {
if (textV.contentOffset.y >= textV.contentSize.height - textV.frame.size.height)
{
button.isHidden = false
}
}
}
Thanks for any help in advance :)
UITextView is subclass of UIScrollView and if you look to declaration, you will see, that it is UIScrollViewDelegate by default, so you can remove the UIScrollViewDelegate at the declaration of your controller. Instead, make your controller UITextViewDelegate which allows it to call scrollViewDidScrollMethod.
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView! {
didSet {
textView.delegate = self
}
}
#IBOutlet weak var button: UIButton! {
didSet {
button.hidden = true
}
}
func scrollViewDidScroll(scrollView: UIScrollView) {
button.hidden = scrollView.contentOffset.y + scrollView.bounds.height < scrollView.contentSize.height
}
}
(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
float bottomEdge = scrollView.contentOffset.y + scrollView.frame.size.height
if (bottomEdge >= scrollView.contentSize.height) {
self.yourButtonName.hidden = true
}
}
If the button is in the last of view(self.view) then I think you have to check that your contentOffset point is at the bottom of contentSize. So you could probably do something like:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
float bottomEdge = scrollView.contentOffset.y +scrollView.frame.size.height;
if (bottomEdge >= scrollView.contentSize.height) {
self.yourButtonName.hidden = true
}
}

(swift) update a number to label will make the view get back to original position

demo image
When I update a number to label will make the view get back to original position.
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet var aview: UIView!
var number = 0
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func plus(sender: UIButton) {
number++
label.text = "number:\(number)"
}
#IBAction func move(sender: AnyObject) {
aview.frame.origin.y -= 20
}
}
I couldn't find the answer on web, please help me to fix this problem.Thank you very much!
Because your xib or Storyboard you set use Autolayout:
So if you don't set constrain system will auto generate it. When you change frame by set frame it effect but when you access to it. It will auto back to old position.
if you don't want it happen. You set in viewDidLoad:
self.view.translatesAutoresizingMaskIntoConstraints = false
Issue is probably related to a constraint reloading when the label reloads.
Instead of setting aview.frame.origin.y -= 20 you should make an outlet to the constraint holding the y position of your aView and then update the constant of that constraint outlet instead.

Swift NSTimer and IBOutlet Issue

I'm using NSTimer to update an image's position on the screen to give the illusion of movement. It's a flappy bird clone I'm creating to learn Swift. Anyway, I'm also updating an outlet by displaying an incrementing Int as the score. However, every time I update the Int and the corresponding outlet, the images on the screen reset to their starting point (bird and tubes). Very odd. Has anyone else come across this? What am I doing wrong?
#IBOutlet weak var tube1: UIImageView!
#IBOutlet weak var bird1: UIImageView!
#IBOutlet weak var score: UILabel!
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(0.02, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
bird1.center=CGPointMake(50,bird1.center.y+CGFloat(num));
tube1.center=CGPointMake(tube1.center.x-CGFloat(num2),tube1.center.y);
if(tube1.center.x<(-40)){
tube1.center.x=screenWidth;//variable set outside this method
tube1.center.y=0;//will be random
updateMyScore();
}
}
func updateMyScore(){
myScore=++;
score.text="Score: \(myScore)"
}
The weird thing is if I comment out the score.text="Score:(myScore)" line everything works fine, but I'd like to have the score show on the screen. Any suggestions?
AutoLayout is running and resetting the position of your images. It is running because you are updating your UILabel. There are 2 ways you can deal with this:
Disable AutoLayout OR
Store the positions of your tubes and pipes in properties and then set them in an override of viewDidLayoutSubviews().
Here is how you might implement option #2:
#IBOutlet weak var tube1: UIImageView!
#IBOutlet weak var bird1: UIImageView!
#IBOutlet weak var score: UILabel!
var tube1center: CGPoint?
var bird1center: CGPoint?
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(0.02, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
bird1.center=CGPointMake(50,bird1.center.y+CGFloat(num));
tube1.center=CGPointMake(tube1.center.x-CGFloat(num2),tube1.center.y);
if(tube1.center.x<(-40)){
tube1.center.x=screenWidth;//variable set outside this method
tube1.center.y=0;//will be random
updateMyScore();
}
bird1center = bird1.center
tube1center = tube1.center
}
func updateMyScore(){
myScore=++;
score.text="Score: \(myScore)"
}
override func viewDidLayoutSubviews() {
if let newcenter = tube1center {
tube1.center = newcenter
}
if let newcenter = bird1center {
bird1.center = newcenter
}
}
Yes, this is well known behavior of auto layout. If you do anything that causes the auto layout engine to reapply the constraints to the view (such as updating the score), any adjustments to layout-related properties will be lost, reset to their values as dictated by the constraints.
As Vacawama pointed out, you could turn off auto layout. Alternatively, rather than manually changing the frame in your timer routine, you could instead create an IBOutlet for the constraints, themselves, and you can them modify the constraint's constant property and then call layoutIfNeeded. That way, if you happen to do something else that triggers the constraints, everything will be fine.