There is a Main View with subview. I need to get these subviews.
For example, I created a view:
With the Swift Code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// Check if has view in rect area
let rect1 = CGRect(x: 0, y: 0, width: 100, height: 100)
if CGRectContainsPoint(rect1, rect1.origin) { // return true
print("TRUE")
} else {
print("FALSE")
}
}
}
I need to get the view you are "touching" the Rect in size or origin.
In the above example, I created three subviews with different colors between them.
I need to get the view and make a print() with the backgroundColor.
Can someone help me?
This func fix the problem:
func intersectingViewWithView(panView: UIView) -> UIView? {
for view in self.view.subviews {
if view != panView {
if CGRectIntersectsRect(panView.frame, view.frame) {
return view
}
}
}
return nil
}
Related
I have a function in my controller I call
private func toggleLauncher() {
let launcher = CommentsLauncher()
launcher.showLauncher()
}
This essentially adds a view on top of the current view, with a semi transparent background.
I'd like to then render a custom inputAccessoryView at the bottom of the newly added view.
class CommentsLauncher: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
}
func showLauncher() {
if let window = UIApplication.shared.keyWindow {
window.addSubview(view)
}
}
override var inputAccessoryView: UIView? {
get {
let containerView = UIView()
containerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
containerView.backgroundColor = .purple
return containerView
}
}
override var canBecomeFirstResponder: Bool {
return true
}
}
All that happens though is the semi transparent background is visible but I see no inputAccessoryView added to the view also and I am unsure why.
Your CommentsLauncher never become the first responder in the code you provided. A UIResponder's inputAccessoryView is displayed when the responder becomes first responder.
Change your showLauncher method to something like this:
func showLauncher() {
if let window = UIApplication.shared.keyWindow {
window.addSubview(view)
becomeFirstResponder()
}
}
And you should see the input accessory view.
import UIKit
class ViewController: UIViewController {
// MARK: -property
// lazy var testBtn: UIButton! = {
// var btn: UIButton = UIButton()
// btn.backgroundColor = UIColor.red
// print("testBtn lazy")
// return btn
// }()
// MARK: -life cycle
override func viewDidLoad() {
super.viewDidLoad()
print("View has loaded")
// set the superView backgroudColor
// self.view.backgroundColor = UIColor.blue
// add testBtn to the superView
// self.view.addSubview(self.testBtn)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("View will appear")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("View has appeared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("View will disappear")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("View has desappeared")
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
print("SubViews will layout")
// layout subViews
// 'CGRectMake' is unavailable in Swift
// self.testBtn.frame = CGRectMake(100, 100, 100, 100)
// self.testBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 100) // CGFloat, Double, Int
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("SubViews has layouted")
// let testBtn_Width = self.testBtn.frame.width
// print("testBtn's width is \(testBtn_Width)")
}
}
The result:
View has loaded
View will appear
SubViews will layout
SubViews has layouted
SubViews will layout
SubViews has layouted
View has appeared
As you see, I have created a new project and type some simple code.
I didn't change the size of the viewController's view.
Why are "SubViews has layouted" and "SubViews will layout" console two times?
Why are viewDidLayoutSubviews and viewWillLayoutSubviews called two times?
Because whenever setNeedsLayout or setNeedsDisplayInRect is being called internally, LayoutSubviews is also being called (once per run loop) on any given view. This applies for example if the view has been added, scrolled, resized, reused etc.
Here is a ViewController that creates 4 subviews using init(repeating:count).
In viewDidLoad I add them as subviews and set their frames. When I run the application only the last view is added.
class ViewController: UIViewController {
let subviews = [UIView].init(repeating: UIView(), count: 4)
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<subviews.count {
self.view.addSubview(subviews[i])
self.subviews[i].backgroundColor = UIColor.red
self.subviews[i].frame = CGRect(x: CGFloat(i) * 35, y: 30, width: 30, height: 30)
}
}
}
Here's the same code except instead of using init(repeating:count) I use
a closure. This works fine-- all subviews are added.
class ViewController: UIViewController {
let subviews: [UIView] = {
var subviews = [UIView]()
for i in 0..<4 {
subviews.append(UIView())
}
return subviews
}()
override func viewDidLoad() {
//same as above...
}
}
You’ve put the same instance of UIView in your array four times. Your viewDidLoad just ends up moving that single view around. You need to create four separate instances of UIView.
let subviews = (0 ..< 4).map({ _ in UIView() })
Here I have a simple example. im calling FirstResponder in viewDidLoad. But accessory view only shows up after tapping the screen. Why isn't it showing from the start?
class TestViewController: MainPageViewController {
private let accessoryView = UIView() //TextInputView() // MessageInputAccessoryView()
override var inputAccessoryView: UIView {
return accessoryView
}
override var canBecomeFirstResponder: Bool { return true }
override func viewDidLoad() {
super.viewDidLoad()
accessoryView.backgroundColor = .red
accessoryView.frame = CGRect(x: 0, y: 0, width: 300, height: 50)
self.becomeFirstResponder()
// Do any additional setup after loading the view.
let tap = UITapGestureRecognizer(target: self, action: #selector(tappo))
self.view.isUserInteractionEnabled = true
self.view.addGestureRecognizer(tap)
tappo()
}
func tappo() {
self.becomeFirstResponder()
}
}
viewWillAppear is a better place to put the becomesFirstResponder. Try that.
So something was resigning my first responder (as I was using UIPageViewController). So I've added this to my UIViewControler :
override var canResignFirstResponder: Bool { return false }
That's it. Cheers!
I made a UIView subclass that implements custom drawing. Here is the code (please don't mind that this could be done by a UIImageView. I stripped the code of all extras just to show the problem)
#IBDesignable
class TPMSkinnedImageView: UIView {
private var originalImage:UIImage?
private var skinnedImage:UIImage?
#IBInspectable var image: UIImage? {
set {
originalImage = newValue
if(newValue == nil) {
skinnedImage = nil
return
}
skinnedImage = originalImage!
self.invalidateIntrinsicContentSize()
self.setNeedsDisplay()
}
get {
return originalImage
}
}
override func draw(_ rect: CGRect) {
let context:CGContext! = UIGraphicsGetCurrentContext()
context.saveGState()
context.translateBy(x: 0, y: rect.height)
context.scaleBy(x: 1, y: -1)
context.draw(skinnedImage!.cgImage!, in: rect)
context.restoreGState()
}
override var intrinsicContentSize: CGSize {
if(skinnedImage != nil) {
return skinnedImage!.size
}
return CGSize.zero
}
}
I instantiate this view in a viewcontroller nib file and show the viewcontroller modally.
What happens is is that the draw method only gets called when the parent view has been on screen for about 20 seconds.
I checked the intrinsicContentSize and it does not return .zero
This is what the stack looks like once it is called:
Any idea what could be causing this?
Try calling setNeedsDisplay() on your view in your view controller's viewWillAppear()