#IBOutlet var green1: UIImageView!
#IBOutlet var red1: UIImageView!
#IBOutlet var blue1: UIImageView!
#IBAction func red(sender: UIButton) {
green1.hidden = true
red1.hidden = false
blue1.hidden = true
}
I want to add and remove objects when the button is pressed.
At the moment they hide and are visible, but i want to remove them completely form the scene when the button is pressed.
And i want the one that is not hidden to appear.
i tried add child and subview but it didn't work the code is in GameViewController.
If you are showing/hiding frequently, changing hidden property is ok, however if you want to remove completely you need to remove the particular image view from its super view.
ex - green1.removeFromSuperView() and when you need it, you have to add as subview and while adding provide its frame.
Related
Why when I pass data to a UILabel directly in the Second View Controller it turns to be nil but when I pass data to a variable first and then apply it to the UILabel everything works fine?
The following code crash the app after segue performed (theResult is nil):
Second View Controller:
#IBOutlet weak var theResult: UILabel!
Main View Controler:
secondVC.theResult.text = “Nice”
But when I create a variable in the Second View Controller, I can pass the data to it easily and then apply it to the UILabel without any problem:
Second View Controller:
var calculation: String?
#IBOutlet weak var theResult: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
theResult.text = calculation
}
Main View Controler:
secondVC.calculation = “Nice”
Why is that?
Note: The UILabel has a default value already when it is created in the Storyboard.
I am almost sure that this is not working but I want to know the reason. Why you can easily change for example the background of the Second View Controller like this:
secondVC.view.backgroundColor = .green
but when you touch the IBOutlets it do not work.
I've 15 Labels in my Storyboard they are just texts, also set from storyboard, What I want to do is to style them, but programitically, Therefore I need to create 15 IBOutlets in my ViewController, I wonder if there is any other way of doing that, without 15 IBOutlets,if it's possible to create 1 IBOutlet and attach all of them to that one? because creating 15 of them is kinda stressing...
You can do this with Outlet Collections instead of an IBOutlet for all the labels you want to group together:
One way to do it is to ctrl+drag from your storyboard to your editor and select outlet collection
This will create #IBOutlet weak var labelCollection: UILabel! in your code
This works fine but then you need to add an additional check for the type when looping:
#IBOutlet weak var labelCollection: UILabel!
func setCustomLayout()
{
for label in labelCollection2.subviews
{
if let label = label as? UILabel
{
// do your custom set up here
}
}
}
What I like to do is to create the specific outlet collection in code first if I way to track the same type like so:
#IBOutlet var labelCollection: [UILabel]!
The I drag from the editor to the storyboard
Then I can work with it as follows
#IBOutlet var labelCollection: [UILabel]!
func setCustomLayout()
{
for label in labelCollection
{
// do your customization here
}
}
Then you can loop through the UIViews inside the IBOutletCollection and do the needful
I am trying to make an app that utilizes some search feature and I am trying to make it so that after the search button is pressed, a view (which contains the search results) moves up from the bottom of the superview and replaces the search view. On the storyboard, the resultsView (of type UIView) is constrained so that its top is equal to the superview's bottom. After the search button is pressed, I would like to animate the view to move up and replace the view already at the bottom of the superview. The problem is, in the viewcontroller's class, when I call the resultsView, the animateWithDuration(NSTimeInterval) that is supposed to be associated with the UIView class is not appearing for me. May this be because the view is already constrained in place? Here is the code, simplified for this post:
import UIKit
import MapKit
class MapViewController: UIViewController, CLLocationManagerDelegate,
MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var slider: UISlider!
#IBOutlet weak var distanceLabel: UILabel!
#IBOutlet weak var searchButton: UIButton!
#IBOutlet weak var searchView: UIView!
#IBOutlet weak var resultView: UIView!
#IBOutlet weak var resultNameLabel: UILabel!
#IBOutlet weak var resultDistanceLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
self.resultView.isHidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func sliderAdjusted(_ sender: Any) {
let int = Int(slider.value)
switch int {
case 1:
distanceLabel.text = "1 mile"
default:
distanceLabel.text = "\(int) miles"
}
}
#IBAction func searchButtonPressed(_ sender: Any) {
/*This is where, after calling a search function which is omitted
from this example, I would like to make the resultsView not
hidden and then animate it to sort of eclipse the search view*/
self.resultView.isHidden = false
self.resultView.animate(withDuration: NSTimeInterval)
/*The above line of code is not actually appearing for me.
After typing "self.resultView." the animate function is not being
given to me as an option for my UIView*/
}
}
I will also attach some images of the view controller so you can sort of get the idea. The results view is not visible in this image because its top is constrained to the superview's bottom, thus it is just out of the visible representation of its superview.
The first image is the view controller with the searchView highlighted. This is the view that I would like to be eclipsed by my resultView after the searchButton is pressed.
The second image is the same view controller with the resultView highlighted. As you can see, its top is constrained to be equal to the superview's bottom. This is the view that I would like to animate upwards into the superview and eclipse the searchView after the search button is pressed.
The methods for all the animate family are all class methods. Which means you call them on the class object not an instance.
You are trying to call
class func animate(withDuration: TimeInterval, animations: () -> Void)
so your code needs to look like
UIView.animate(withDuration: 0.5) {
//the things you want to animate
//will animate with 0.5 seconds duration
}
In the particular case it looks like you are trying to animate the height of resultView so you need an IBOutlet to that constraint. You could call it resultViewHeight.
UIView.animate(withDuration: 0.5) {
self.resultViewHeight.constant = theDesiredHeight
self.layoutIfNeeded()
}
Calling layoutIfNeeded() within the closure is the secret sauce to animating auto layout. Without that the animation will just jump to the and point.
I'm new to Swift/macOS dev, plenty of dev experience otherwise though. Just trying to make something rudimentary.
Here's my app storyboard:
I'm trying to get:
the Touch Bar slider to change when the slider on the main window changes
vice versa
update the Touch Bar Label button with the Int value of the slider.
Q) How do I achieve this?
Note: The main window slider control is wired up and working when I manipulate it e.g.
#IBOutlet weak var mySlider: NSSlider!
#IBAction func mySlider_Changed(_ sender: NSSlider) {
//... stuff happens here.
}
You'll want your view controller to have some explicit model/state of what the value of these sliders have. e.g.
class ViewController : NSViewController {
var value: Double
}
Then you can connect the sliders and textfield to update or display this value.
Approach 1: Target/Action/SetValue
This follows the use of explicit IBActions that you had started. In response to that action, we'll pull the doubleValue from the slider and update the ViewController's model from that:
#IBAction func sliderValueChanged(_ sender: NSSlider) {
value = sender.doubleValue
}
The second piece is updating everything to reflect that new value. With Swift, we can just use the didSet observer on the ViewController's value property to know when it changes and update all of the controls, e.g:
#IBOutlet weak var touchBarSlider: NSSlider!
#IBOutlet weak var windowSlider: NSSlider!
#IBOutlet weak var windowTextField: NSTextField!
var value: Double {
didSet {
touchBarSlider.doubleValue = value
windowSlider.doubleValue = value
windowTextField.doubleValue = value
}
}
And that's it. You can add a number formatter to the textfield so it nicely displays the value, which you can do in Interface Builder or programmatically. And any other time you change the value, all of the controls will still get updated since they are updated in the didSet observer instead of just the slider action methods.
Approach 2: Bindings
Bindings can eliminate a lot of this boiler plate code when it comes to connecting model data to your views.
With bindings you can get rid of the outlets and the action methods, and have the only thing left in the view controller be:
class ViewController: NSViewController {
#objc dynamic var value: Double
}
The #objc dynamic makes the property be KVO compliant, which is required when using bindings.
The other piece is establishing bindings from the controls to our ViewController's value property. For all of the controls this is done by through the bindings inspector pane, binding the 'Value' of the control to the View Controller's value key path:
And that's it. Again, you could add a number formatter to the textfield, and any other changes to the value property will still update your controls since it will trigger the bindings to it. (you can also still use the didSet observer for value to make other changes that you can't do with bindings)
I am trying to add a custom view programmatically to my view controller. I used this snippet of code with no success of it appearing in front of my main view controller.
var DynamicView = CustomFilter()
DynamicView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(DynamicView)
CustomFilter Class:
import UIKit
class CustomFilter:
UIView {
#IBOutlet weak var party: UIButton!
#IBOutlet weak var outdoors: UIButton!
#IBOutlet weak var sports: UIButton!
#IBOutlet weak var diner: UIButton!
#IBOutlet weak var music: UIButton!
#IBOutlet weak var gaming: UIButton!
}
The custom filter is connected to a xib file.
Xib File:
Is there a possibility that the custom view maybe out of placed? I'm not sure what I'm doing wrong.
In order to use a view we designed in a xib, we most load from the xib.
if
let bundle = NSBundle(forClass: CustomFilter.self),
let nib = bundle.loadNibNamed("<#Xib File Name#>", owner: self, options: nil),
let dynamicView = nib.first as? CustomFilter {
self.view.addSubview(dynamicView)
}
An alternative approach would be to write your CustomFilter's init to load the view from the xib itself.
More clearly, the problem you're having is that none of your CustomFilter's initializers are going to care about the xib file you made unless you write them and tell them to care about it. Your current code is returning a 0x0 view with probably a white or clear background. If you modified your current code to set the CustomFilter's frame to something other than 0x0 size and set the background color to something like UIColor.greenColor(), you'd see it clear as day.
Also, you could use Xcode's visual debugger to find it.
It's probably zero height and zero width, and may be off-screen also.
You need to give it height and width constraints and x and y position constraints.
You should probably also use CustomFilter(frame: someFrameRect), since as I recall initWithFrame is the designated initializer for UIView.
As an aside, variable names should start with a lower-case letter, so DynamicView should be dynamicView