I have a UITextField & UIButton placed inside a vertical UIStackView. Programatically, I've added a UIView to serve as an underline of the UITextField.
The problem comes when I compile the code. The line is longer than the text field. I've printed the width of all of the objects above and it says 335.
I call this function in viewWillAppear and the line is longer. If I call it in viewDidAppear, the line is the exact width of the UITextField but you can see the button and text field flash very briefly before updating the view. What am I doing wrong?
override func viewDidLoad() {
super.viewDidLoad()
observeKeyboardNotifications()
textFieldDelegate()
setupRegisterButton()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupTextFields()
}
func setupTextFields() {
emailTextField.leftViewMode = .always
let emailIconView = UIImageView()
emailIconView.frame = CGRect(x: 0, y: 0, width: 23, height: 17)
emailIconView.image = UIImage(named: "icon_email")
let bgIconView = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 17))
bgIconView.addSubview(emailIconView)
emailTextField.leftView = bgIconView
emailTextField.tintColor = .white
emailTextField.textColor = .white
emailTextField.backgroundColor = .red
emailTextField.borderStyle = .roundedRect
let bottomLineEmail = CALayer()
bottomLineEmail.frame = CGRect(x: 0, y: 29, width: emailTextField.frame.width, height: 1)
print("Email width", emailTextField.frame.width)
print("button width", retrievePasswordButton.frame.width)
print("line width", bottomLineEmail.frame.width)
bottomLineEmail.backgroundColor = UIColor.white.cgColor
emailTextField.layer.addSublayer(bottomLineEmail)
//emailTextField.backgroundColor = .clear
emailTextField.attributedPlaceholder = NSAttributedString(string : emailTextField.placeholder!,
attributes : [NSAttributedStringKey.foregroundColor: Colors.authTextFieldPlaceholderColor])
retrievePasswordButton.isEnabled = false
handleTextFields()
}
I checked it personally
it works in ViewWillLayoutSubviews
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews();
self.setupTextFields()
}
and viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setupTextFields();
}
Related
I am following a tutorial to create a swift app that adds a number of views to a scroll view and then allows me to scroll between them. I have the app working and understand it for the most part. When I change the orientation of the device the views width don't get updated so I have parts of more than one view controller on the screen? Does anybody know how to fix this? From my understanding I need to call something in the viewsDidTransition method to redraw the views. Any help would be greatly appreciated. Thanks!
Here is what I have so far:
import UIKit
class ViewController: UIViewController {
private let scrollView = UIScrollView()
private let pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.numberOfPages = 5
pageControl.backgroundColor = .systemBlue
return pageControl
}()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
pageControl.addTarget(self,
action: #selector(pageControlDidChange(_:)),
for: .valueChanged)
scrollView.backgroundColor = .red
view.addSubview(scrollView)
view.addSubview(pageControl)
}
#objc private func pageControlDidChange(_ sender: UIPageControl){
let current = sender.currentPage
scrollView.setContentOffset(CGPoint(x: CGFloat(current) * view.frame.size.width,
y: 0), animated: true)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
pageControl.frame = CGRect(x: 10, y: view.frame.size.height - 100, width: view.frame.size.width - 20, height: 70)
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height - 100)
if scrollView.subviews.count == 2 {
configureScrollView()
}
}
private func configureScrollView(){
scrollView.contentSize = CGSize(width: view.frame.size.width*5, height: scrollView.frame.size.height)
scrollView.isPagingEnabled = true
let colors: [UIColor] = [.systemRed, .systemGray, .systemGreen, .systemOrange, .systemPurple]
for x in 0..<5{
let page = UIView(frame: CGRect(x: CGFloat(x) * view.frame.size.width, y: 0, width: view.frame.size.width, height: scrollView.frame.size.height))
page.backgroundColor = colors[x]
scrollView.addSubview(page)
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
print("hello world")
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
pageControl.currentPage = Int(floorf(Float(scrollView.contentOffset.x) / Float(scrollView.frame.size.width)))
}
}
hi fellow developer I want to swipe between uiview with scrollView while changing the the index and small indicator move left and right. but is not responding while I try to swipe. this is my picture and my setup to scroll between uiview. can you tell me where I am missing?
let segmentedControl = UISegmentedControl()
let containerView = UIView()
let indicatorView = UIView()
let leftView = UIView()
let rightView = UIView()
let scrollView = UIScrollView()
var slides = [UIView]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
slides.append(leftView)
slides.append(rightView)
segmentedControl.insertSegment(withTitle: "Harian", at: 0, animated: true)
segmentedControl.insertSegment(withTitle: "Mata Pelajaran", at: 1, animated: true)
segmentedControl.selectedSegmentIndex = 0
segmentedControl.addTarget(self, action: #selector(handleTap), for: .valueChanged)
setupSlideScrollView()
}
func setupSlideScrollView() {
view.addSubview(scrollView)
scrollView.isPagingEnabled = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
for i in 0..<slides.count {
slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(slides[i])
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x / view.frame.width)
segmentedControl.selectedSegmentIndex = Int(pageIndex)
}
#objc func handleTap(_ sender: UISegmentedControl) {
indicatorView.frame.origin.x = (segmentedControl.frame.width / CGFloat(segmentedControl.numberOfSegments)) * CGFloat(segmentedControl.selectedSegmentIndex)
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
self.indicatorView.transform = CGAffineTransform(scaleX: 0.7, y: 1)
}) { (finish) in
UIView.animate(withDuration: 0.4, animations: {
self.indicatorView.transform = CGAffineTransform.identity
})
}
}
I am trying to make a game where if I press a button it can spawn another button in another area so you can click and keep doing that, every time you press the button you should get a point. I don't know how to spawn another button when I pressed one button.
// this is the code
var monkeyPosition : Int = 1
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.addSubview(makeButtonSpawn())
view.addSubview(makeButtonSpawn2())
}
#IBAction func monkeyPlayer(_ sender: UIButton) {
if sender.tag == 1 && (monkeyPosition == 1) {
makeButtonSpawn2().isHidden = false
}
}
func makeButtonSpawn() -> UIButton {
let monkey = UIButton(type: UIButton.ButtonType.system)
//Set a frame for the button. Ignored in AutoLayout/ Stack Views
monkey.frame = CGRect(x: 30, y: 30, width: 90, height: 90)
monkey.backgroundColor = UIColor.blue
makeButtonSpawn().isHidden = true
return monkey
}
func makeButtonSpawn2() -> UIButton {
let monkey = UIButton(type: UIButton.ButtonType.system)
//Set a frame for the button. Ignored in AutoLayout/ Stack Views
monkey.frame = CGRect(x: 80, y: 80, width: 90, height: 90)
monkey.backgroundColor = UIColor.blue
makeButtonSpawn2().isHidden = true
return monkey
}
Create instance variables for your buttons, then you will be able to access them from places in your class. Also you can set its properties inside variable closure instead of declaring method
class ViewController: UIViewController {
var button1: UIButton = {
let button = UIButton()
button.frame = CGRect(x: 30, y: 30, width: 90, height: 90)
button.backgroundColor = .blue
return button
}()
var button2: UIButton = {
let button = UIButton()
button.frame = CGRect(x: 80, y: 80, width: 90, height: 90)
button.backgroundColor = .blue
button.isHidden = true
return button
}()
}
Next, you need to add your buttons as subviews to main view and you need to add target for them
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.addSubview(button1)
view.addSubview(button2)
button1.addTarget(self, action: #selector(button1Pressed(_:)), for: .touchUpInside)
button2.addTarget(self, action: #selector(button2Pressed(_:)), for: .touchUpInside)
}
#objc func button1Pressed(_ sender: UIButton) {
}
#objc func button2Pressed(_ sender: UIButton) {
}
Finally, you can unhide second button when first button is pressed
#objc func button1Pressed(_ sender: UIButton) {
if monkeyPosition == 1 {
button2.isHidden = false
}
}
I called a performSegue from a tableView and pushed to a FormVC. However, my header went underneath the navigationBar despite that the UIView is offset 100 pts in the y axis.
My code as follows:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EventsDetails" {
let destVC = segue.destination as! EventsDetailsViewController
}
}
class EventsDetailsViewController: FormViewController {
override func viewDidLoad() {
super.viewDidLoad()
form +++
Section(){ section in
section.header = {
var header = HeaderFooterView<UIView>(.callback({
let view = UIView(frame: CGRect(x: 0, y: 100, width: 100, height: 180))
let imageView = UIImageView(frame: CGRect(x: 20, y: 10, width: 80, height: 80))
imageView.backgroundColor = .red
imageView.layer.cornerRadius = imageView.frame.size.width / 2
imageView.clipsToBounds = true
let nameLabel = UILabel(frame: CGRect(x: 120, y: 40, width: 150, height: 20))
nameLabel.text = "Test Text"
nameLabel.backgroundColor = .blue
nameLabel.font = UIFont.boldSystemFont(ofSize: 18.0)
view.addSubview(imageView)
view.addSubview(nameLabel)
view.backgroundColor = .white
return view
}))
header.height = { 200 }
return header
}()
}
}
}
Is there a way to move the view down to the bottom of the navBar? By the way I use storyboard. I know this may be a primitive question, but some advice is much appreciated, thanks!
I currently have a subclass of UIView which contains numerous subviews. I wish to add a UISwipeGesture to the subviews but unfortunately the swipe gesture is not recognized. I've set userInteractionEnabled = true and direction of the swipe gesture but nothing works.
public class CardStackView: UIView{
public var dataSource = [UIImage]()
private var swipeGuesture: UISwipeGestureRecognizer!
override public func layoutSubviews() {
for img in dataSource{
let view = AppView(image: img, frame: self.frame)
self.addSubview(view)
}
animateSubview()
self.userInteractionEnabled = true
}
func animateSubview(){
for (index, sView) in self.subviews.enumerate() {
swipeGuesture = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeGuestureDidSwipeRight(_:)))
swipeGuesture.direction = .Right
sView.addGestureRecognizer(swipeGuesture)
sView.userInteractionEnabled = true
let move: CGFloat = CGFloat(-20 + index * 20)
let opacity = Float(1 - 0.2 * CGFloat(index))
sView.shadowOpacity(opacity).shadowOffset(CGSizeMake(20 - CGFloat(index) * 5, 20 - CGFloat(index) * 5)).shadowRadius(5).moveX(-move).moveY(-move).gravity().shadowColor(UIColor.grayColor()).duration(1)
.completion({
}).animate()
}
}
func swipeGuestureDidSwipeRight(gesture: UISwipeGestureRecognizer) {
print("Swiped right")
let subview = self.subviews[0]
subview.moveX(-60).duration(1).animate()
}
}
Example
class ExampleController: UIViewController {
var stackView: CardStackView!
override func viewDidLoad() {
super.viewDidLoad()
stackView = CardStackView(frame: CGRect(x: 20, y: 80, width: 200, height: 200))
stackView.dataSource = [UIImage(named: "2008")!, UIImage(named: "2008")!]
self.view.addSubview(stackView)
}
}
self.view.bringSubviewToFront(yourSubview)
try this code for all your subviews and if it doesn't work try this in your controller class for your CardStackView.
Try to call setNeedsLayout for stackView:
override func viewDidLoad() {
super.viewDidLoad()
stackView = CardStackView(frame: CGRect(x: 20, y: 80, width: 200, height: 200))
stackView.dataSource = [UIImage(named: "2008")!, UIImage(named: "2008")!]
stackView.setNeedsLayout()
self.view.addSubview(stackView)
}