How can I get current constraints and set them later for a UIView. Am I doing this correctly?
Current Attempt:
Get Current Constraints
// get current constraints
var txtViewConstraints = txtView.constraints()
Set Constraints Later
override func viewDidLayoutSubviews() {
if txtViewConstraints.isEmpty == false {
txtView.addConstraints(txtViewConstraints)
}
}
Edit: This is a followup to this question: BringSubViewToFront Repositions UIView in AutoLayout
Update Code Used to Move txtView:
#IBAction func moveTxtView(sender: UIPanGestureRecognizer) {
var translation: CGPoint = sender.translationInView(self.view)
sender.view?.center = CGPointMake(sender.view!.center.x + translation.x, sender.view!.center.y + translation.y)
sender.setTranslation(CGPointMake(0, 0), inView: self.view)
txtViewConstraints = txtView.constraints()
txtViewPosition = CGRect(x: txtView.frame.origin.x, y: txtView.frame.origin.y, width: txtView.frame.size.width, height: txtView.frame.size.height)
}
Related
I've been trying to create a sliding transition from one child view controller to another inside an NSPopover.
My problem is that the child view controllers do not stick to the top of the NSPopover during the transition. They animate in from the bottom or top:
Expected behaviour: both child view controllers should stick to the top during the transition and should simply slide over horizontally.
This is the function I wrote to trigger the transition:
func loadViewController(_ childViewController: NSViewController, withTransition transitionOptions: NSViewController.TransitionOptions?) {
addChild(childViewController)
view.addSubview(childViewController.view)
childViewController.view.layer?.borderColor = NSColor(calibratedRed: 0, green: 255, blue: 0, alpha: 1).cgColor
childViewController.view.layer?.borderWidth = 2
childViewController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
view.layout()
let oldViewController = currentViewController
currentViewController = childViewController
oldViewController?.view.layer?.borderColor = NSColor(calibratedRed: 255, green: 0, blue: 0, alpha: 1).cgColor
oldViewController?.view.layer?.borderWidth = 2
if let oldViewController = oldViewController {
transition(from: oldViewController, to: currentViewController!, options: transitionOptions ?? .slideLeft, completionHandler: { [weak oldViewController] in
oldViewController?.removeFromParent()
oldViewController?.view.removeFromSuperview()
})
}
NSAnimationContext.runAnimationGroup({ (context) -> Void in
context.duration = 0.5
context.allowsImplicitAnimation = true
self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
})
}
Any idea what could be causing the issue? I've tried playing around with the constraints of both the child and parent view controllers as well as their frame sizes. I just can't figure out what I'm doing wrong.
I've uploaded the complete reproducible example here: https://github.com/maximilianschmitt/DebugPopoverAnimation
MasterViewController.swift
ChildViewController.swift
Thanks a lot for your help!
If you expect as on below animation
then just remove update of content size from animation block, as below
self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
NSAnimationContext.runAnimationGroup({ (context) -> Void in
context.duration = 0.5
context.allowsImplicitAnimation = true
}) {
oldViewController?.removeFromParent()
oldViewController?.view.removeFromSuperview()
}
Update: keep popover content animatable (above changes are not needed)
For this case the only you need is to flip coordinate system for popover content view (which is a view of MasterViewController)
class PopoverContentView: NSView {
override var isFlipped: Bool { true }
}
class MasterViewController: NSViewController {
...
override func loadView() {
self.view = PopoverContentView()
}
I am building an e-commerce app and would like to create the attached image.
I am presenting this controller Modally therefore, it will not be inside a Tabbar.
Is there an easy way I can add the Tabbar and create the button without creating a TabBar like view for each iPhone?
Or would it be best to just embed it into another UITabBarController? Seems overkill...
Many thanks.
Declare Checkout button and views for toolbar & shadow.
lazy var customView: UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 249/255, green: 249/255, blue: 249/255, alpha: 1.0)
vw.translatesAutoresizingMaskIntoConstraints = false
return vw
}()
lazy var shadowView: UIView = {
let vw = UIView()
vw.backgroundColor = UIColor.gray
vw.translatesAutoresizingMaskIntoConstraints = false
return vw
}()
lazy var checkoutButton: UIButton = {
let btn = UIButton(type: .system)
btn.tintColor = .white
btn.layer.cornerRadius = 5
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.setTitle("Checkout", for: .normal)
btn.backgroundColor = UIColor(red: 39/255, green: 39/255, blue: 39/255, alpha: 1.0)
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
Add all in viewDidLoad.
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(customView)
[customView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
//Size of UITabBar from safeArea, so its compatible for iPhone X and others
customView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -49),
customView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
customView.heightAnchor.constraint(equalToConstant: 83)].forEach{ $0.isActive = true }
view.addSubview(shadowView)
[shadowView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
shadowView.bottomAnchor.constraint(equalTo: customView.topAnchor),
shadowView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
shadowView.heightAnchor.constraint(equalToConstant: 0.5)].forEach{ $0.isActive = true }
customView.addSubview(checkoutButton)
[checkoutButton.leadingAnchor.constraint(equalTo: customView.leadingAnchor, constant: 10),
checkoutButton.topAnchor.constraint(equalTo: customView.topAnchor, constant: 4.5),
checkoutButton.trailingAnchor.constraint(equalTo: customView.trailingAnchor, constant: -10),
checkoutButton.heightAnchor.constraint(equalToConstant: 40)].forEach{ $0.isActive = true }
}
I have a UIView Subclass which presents three buttons arranged with two above one. I use a StackView to arrange the top two buttons, and the bottom arranged view is just a single button. The problem is that the button added as an arrangedSubview to the root StackView receives clicks, while the buttons inside of the StackView in the StackView do not.
(note: dependencies should not be affecting anything. DynamicButton is just a cocoapod UIButton subclass. InsetView is my own UIView subclass that embeds the buttons in a view with constraints. And pinTo is just a UIView extension that adds pinning constraints to the view. These things shouldn't be the bug given that the bottom button receives clicks and is under the same conditions as the top two buttons.)
class PathContentView: UIView {
let previousButton: DynamicButton = {
let r = DynamicButton(style: .caretLeft)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
let nextButton: DynamicButton = {
let r = DynamicButton(style: .caretRight)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
let deleteButton: DynamicButton = {
let r = DynamicButton(style: .close)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
init() {
super.init(frame: .zero)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
private func setup() {
// button components
let deleteButtonHolder = InsetView(width: 25, height: 25, view: deleteButton)
let previousButtonHolder = InsetView(width: 25, height: 25, view: previousButton)
let nextButtonHolder = InsetView(width: 25, height: 25, view: nextButton)
let rootStackView = UIStackView()
let topSectionStackView = UIStackView()
topSectionStackView.distribution = .fillEqually
topSectionStackView.alignment = .center
topSectionStackView.spacing = 20
topSectionStackView.axis = .horizontal
rootStackView.axis = .vertical
rootStackView.distribution = .fillEqually
rootStackView.alignment = .fill
rootStackView.isLayoutMarginsRelativeArrangement = true
rootStackView.layoutMargins = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
addSubview(rootStackView)
topSectionStackView.addArrangedSubview(previousButtonHolder)
topSectionStackView.addArrangedSubview(nextButtonHolder)
rootStackView.addArrangedSubview(deleteButtonHolder)
rootStackView.addArrangedSubview(topSectionStackView)
rootStackView.pinTo(superView: self)
rootStackView.isUserInteractionEnabled = true
topSectionStackView.isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
func tapped() {
print("tapped")
}
}
I have update my Project to Swift3 in Xcode 8 and it comes this error but I have no idea what I can make there. I have already search in google but nothing founded.
Have anyone an Idea what I can make ?
Here the Error:
Method 'collectionViewContentSize()' with Objective-C selector 'collectionViewContentSize' conflicts with getter for 'collectionViewContentSize' from superclass 'UICollectionViewLayout' with the same Objective-C selector
public func collectionViewContentSize() -> CGSize {
let numberOfSections = collectionView?.numberOfSections
if numberOfSections == 0 {
return CGSize.zero
}
var contentSize = collectionView?.bounds.size
contentSize?.height = CGFloat(columnHeights[0])
return contentSize!
}
I had something similar but I was overriding collectionViewContentSize()
override func collectionViewContentSize() -> CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}
I Downloaded XCode 8 beta 4 today and have had to change it to:
override var collectionViewContentSize: CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}
Im trying to program a UIButton that performs that prints a message to the console. I can see the button and touch it but as soon as I touch it my app stops running and the console shows the following error:
Game[2743:63724] -[Game.GameScene buttonAction:]: unrecognized selector sent to instance 0x7a11ad00
2014-09-15 17:51:06.106 Game[2743:63724] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GameGameScene buttonAction:]: unrecognized selector sent to instance 0x7a11ad00'
this is my code:
let imageButton = UIImage(named: "playbutton2") as UIImage
let buttonPlay = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
buttonPlay.frame = CGRectMake(screenSize.width / 2 , screenSize.height / 2, 100, 100)
buttonPlay.setImage(imageButton, forState: .Normal)
buttonPlay.addTarget(self, action: Selector("buttonAction:"), forControlEvents: UIControlEvents.TouchUpInside)
buttonPlay.tag = 22
self.view.addSubview(buttonPlay)
and
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
------- COMPLETE CODE ---------
import SpriteKit
class GameScene: SKScene {
var skyColor = SKColor()
var bird = SKSpriteNode()
var moving = SKNode()
var titleLabelNode = SKLabelNode()
var title = NSString()
let imageButton = UIImage(named: "playbutton2") as UIImage
let screenSize: CGRect = UIScreen.mainScreen().bounds
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.addChild(moving)
skyColor = SKColor(red: 113.0/255.0, green: 197.0/255.0, blue: 207.0/255.0, alpha: 1.0)
self.backgroundColor = skyColor
var birdTexture1 = SKTexture(imageNamed: "Bird1")
birdTexture1.filteringMode = SKTextureFilteringMode.Nearest
var birdTexture2 = SKTexture(imageNamed: "Bird2")
birdTexture2.filteringMode = SKTextureFilteringMode.Nearest
var animation = SKAction.animateWithTextures([birdTexture1, birdTexture2], timePerFrame: 0.2)
var flap = SKAction.repeatActionForever(animation)
bird = SKSpriteNode(texture: birdTexture1)
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame) + 150)
bird.runAction(flap)
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height/2.0)
bird.physicsBody.dynamic = false
self.addChild(bird)
var groundTexture = SKTexture(imageNamed: "Ground")
groundTexture.filteringMode = SKTextureFilteringMode.Nearest
var moveGroundSprite = SKAction.moveByX(-groundTexture.size().width, y: 0, duration: NSTimeInterval(0.01 * groundTexture.size().width))
var resetGroundSprite = SKAction.moveByX(groundTexture.size().width, y: 0, duration: 0)
var moveGroundSpritesForever = SKAction.repeatActionForever(SKAction.sequence([moveGroundSprite, resetGroundSprite]))
for var i:CGFloat = 0; i<2 + self.frame.size.width / (groundTexture.size().width); ++i {
var sprite = SKSpriteNode(texture: groundTexture)
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2)
sprite.runAction(moveGroundSpritesForever)
moving.addChild(sprite)
}
title = "Swing Bird"
titleLabelNode.fontName = "Helvetica-Bold"
titleLabelNode.fontSize = 80
//titleLabelNode.fontColor = SKColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.)
titleLabelNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 50)
titleLabelNode.text = "\(title)"
addChild(titleLabelNode)
let buttonPlay = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
buttonPlay.frame = CGRectMake(screenSize.width / 2 , screenSize.height / 2, 100, 100)
buttonPlay.setImage(imageButton, forState: .Normal)
buttonPlay.addTarget(self, action: Selector("buttonAction:"), forControlEvents: UIControlEvents.TouchUpInside)
buttonPlay.tag = 22
self.view.addSubview(buttonPlay)
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Your function buttonAction is defined at the wrong level. It is currently a function inside didMoveToView instead of a function of the class GameScene.
You can fix it like this:
class GameScene: SKScene {
...
// Move the function here!
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
override func didMoveToView(view: SKView) {
...