I'm very new to swift so sorry if this is a basic question or I'm doing something terribly wrong. I've been having some issues trying to add a subview when touching a row on a tableview and have been working off of this page: http://myxcode.net/2015/11/07/adding-a-subview-using-a-xib-and-storyboard/
Here's the relevant code I have so far (I removed some of the tableview logic because that works fine):
Subview Class
class ConfirmTeamView: UIView, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var teamListTableView2: UITableView!
#IBOutlet weak var confirmButton2: UIButton!
#IBOutlet weak var cancelButton2: UIButton!
var playerList: [Player]?
var view: UIView!
init(pList: [Player]) {
self.playerList = pList
super.init(frame: CGRectMake(20, 100, 385, 339))
setup()
teamListTableView2.delegate = self
teamListTableView2.dataSource = self
let playerListTableCellNib = UINib(nibName: "PlayerListTableViewCell", bundle: nil)
teamListTableView2.registerNib(playerListTableCellNib, forCellReuseIdentifier: "PlayerListTableViewCell")
}
required init?(coder aDecoder: NSCoder) {
self.playerList = nil
super.init(coder: aDecoder)
setup()
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleHeight,UIViewAutoresizing.FlexibleWidth]
addSubview(view)
}
func loadViewFromNib () -> UIView
{
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "ConfirmTeamView", bundle: bundle)
//this line I think is causing a stack overflow, any idea why?
let thisview = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return thisview
}
}
and then in my viewController (I again removed some tableview methods for ease of reading):
class ChooseExistingTeamViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var TeamListTableView: UITableView!
var existingTeamsArray = [Team]()
var confirmTeamUI : ConfirmTeamView!
override func viewDidLoad() {
super.viewDidLoad()
TeamListTableView.delegate = self
TeamListTableView.dataSource = self
let testPlayer1 = Player(name: "John", number: 24)
let testPlayer2 = Player(name: "Smith", number: 50)
let testTeam = Team(name: "myTeam", players: [testPlayer1, testPlayer2])
existingTeamsList = [testTeam]
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// This is where I load the subview
TeamListTableView.userInteractionEnabled = false
let selectedTeam = existingTeamsList[indexPath.row]
let confirmTeamUI = ConfirmTeamView(pList: selectedTeam.players)
confirmTeamUI.cancelButton2.addTarget(self, action: "cancelPressed:", forControlEvents: UIControlEvents.TouchUpInside)
let viewWidth = self.view.frame.width
let xWidth = viewWidth - 40
let yHeight = 200
confirmTeamUI.frame = CGRect(x: 20, y: 100, width: Int(xWidth), height: yHeight)
self.view.addSubview(confirmTeamUI)
}
func cancelPressed(sender: UIButton) {
// self.confirmTeamUI.view.removeFromSuperview() [This line throws an exception for unwrapping an optional value]
if self.confirmTeamUI != nil { self.confirmTeamUI.removeFromSuperview() }
else { print("Confirm Team is nil") }
// pressing the cancel button runs the else case
}
Any advice would be very appreciated and please let me know if you need more!
Related
I am using two xib files of UIView. I want to show Custominfoview on pressing button from first xib view which is FirstView. I am little confused here how to do that. My codes is below please tell me how to do that. I have searched a lot but nothing found. I have attached a picture in link which is I exactly want.
class CustominfoView: UIView {
#IBOutlet var mainCustomView: UIView!
#IBOutlet weak var infotextLbl: UILabel!
// MARK:-
// MARK:- Methods
// MARK: UIView Methods
required init(coder aDecoder : NSCoder) {
super.init(coder :aDecoder)!
setup()
}
override init(frame : CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
let view = loadViewFromXib()
view.frame = bounds
// view.autoresizingMask = UIViewAutoresizing.flexibleWidth | UIViewAutoresizing.flexibleHeight
view.layer.cornerRadius = 12
view.layer.borderColor = UIColor.red.cgColor
view.layer.borderWidth = 2
addSubview(view)
}
func loadViewFromXib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustominfoView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
class FirstView: UIView {
#IBOutlet var mainCustomView: UIView!
#IBOutlet weak var infotextLbl: UILabel!
// MARK:-
// MARK:- Methods
// MARK: UIView Methods
required init(coder aDecoder : NSCoder) {
super.init(coder :aDecoder)!
setup()
}
override init(frame : CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
let view = loadViewFromXib()
view.frame = bounds
// view.autoresizingMask = UIViewAutoresizing.flexibleWidth | UIViewAutoresizing.flexibleHeight
view.layer.cornerRadius = 12
view.layer.borderColor = UIColor.red.cgColor
view.layer.borderWidth = 2
addSubview(view)
}
func loadViewFromXib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustominfoView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
#IBAction func infoBtnpressed(_ sender: UIButton) {
print("Pressed")
}
}
}
Just add customInfoView as a subview on top of the first view using addSubview.
(button pressed)
let customInfoView = CustomInfoView()
self.addSubview(customInfoView)
And then when you need to dismiss it simply remove it from the parent.
You can do something like this :
#IBAction func infoBtnpressed(_ sender: UIButton) {
print("Pressed")
let customInfoView = CustomInfoView(frame: CGRect(x: 100, y: 100, width: 200, height: 200) )
self.addSubView(customInfoView)
}
In CGRect pass the frame value as desired. Also you should declare the customInfoView as global so that you can remove it easily.
I am working on iOS application in swift 3.0 where I am creating custom view with textfield and button calculate values for all text filed and display the sum of all textfield on the top totalText.
Code for MainViewController:
#IBOutlet weak var totalText: UITextField!
var totalview:[UIView]!
override func viewDidLoad() {
yvalue = 1
tag = 1
count = 1
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func actionButton(_ sender: UIButton) {
yvalue = 55 + yvalue
//for i in 0...count {
extraview = View(frame: CGRect(x: 50, y: 75+yvalue, width: 350, height: 50))
extraview.backgroundColor = UIColor(white: 1, alpha: 0.5)
extraview.layer.cornerRadius = 15
extraview.tag = tag
print("ExtraView tag=",extraview.tag)
extraview.ActionButtonsub.addTarget(self, action: (#selector(cancelbutton(_:))), for: UIControlEvents.touchUpInside)
extraview.textFiled.addTarget(self, action: #selector(didChangeTexts(textField:)), for: .editingChanged)
extraview.textFiled.tag = tag
print("text tag=",extraview.textFiled.tag)
self.view.addSubview(extraview)
count = count + 1
tag = tag + 1
//}
}
func cancelbutton(_ sender: UIButton) {
extraview.removeFromSuperview()
}
func didChangeTexts(textField: UITextField) {
totalText.text = extraview.textFiled.text
}
Code for UIView:
class View: UIView {
#IBOutlet var subView: UIView!
#IBOutlet weak var textFiled: UITextField!
#IBOutlet weak var ActionButtonsub: UIButton!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Bundle.main.loadNibNamed("View",owner: self, options:nil)
self.addSubview(self.subView)
}
override init(frame: CGRect) {
super.init(frame: frame)
Bundle.main.loadNibNamed("View", owner: self, options: nil)
subView.frame = bounds
self.addSubview(self.subView)
}
}
Sample Output
If you think #Scriptable way is complex then go like below..
Simple way, you can add those textfields into one collection while creating & looping it when you need to do something.
Something like this should work, may need a little modification.
You just need to iterate through the subviews, get the textfield for each view, convert to double value and add them up along the way.
func calculateTotal() -> Double {
var total: Double = 0.0
for subview in self.view.subviews {
if let v = subview as? View, !v.textFiled.isEmpty {
total += Double(v.textFiled.text)
}
}
return total
}
An alternative is applying filter, flatMap and reduce functions
let sum = (view.subviews.filter{$0 is View} as! [View]) // filters all `View` instances
.flatMap{$0.textFiled.text} // maps all text properties != nil
.flatMap{Double($0)} // maps all values which are convertible to Double
.reduce(0.0, {$0 + $1}) // calculates the sum
I have completed all the needed code for delegate to work. In my viewcontroller:
class ViewController: UIViewControllerCustomViewDelegate
I also have this:
override func viewDidLoad() {
super.viewDidLoad()
let myCustomView = Bundle.main.loadNibNamed("ImageHeaderView", owner: self, options: nil)?[0] as! ImageHeaderView
myCustomView.delegate = self
}
func goToNextScene() {
print("GOTOSCENE2")
}
And in my custom view I have this:
import UIKit
protocol CustomViewDelegate: class { // make this class protocol so you can create `weak` reference
func goToNextScene()
}
#available(iOS 10.0, *)
class ImageHeaderView : UIView {
#IBOutlet weak var followme: UISwitch!
#IBOutlet weak var profileImage : UIImageView!
#IBOutlet weak var backgroundImage : UIImageView!
weak var delegate: CustomViewDelegate?
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor(hex: "E0E0E0")
self.profileImage.layer.cornerRadius = self.profileImage.frame.size.height / 2
self.profileImage.clipsToBounds = true
self.profileImage.layer.borderWidth = 1
self.profileImage.layer.borderColor = UIColor.white.cgColor
//self.profileImage.setRandomDownloadImage(80, height: 80)
//self.backgroundImage.setRandomDownloadImage(Int(self.frame.size.width), height: 100)
}
#IBAction func followme(_ sender: AnyObject) {
UserDefaults.standard.set(followme.isOn, forKey: "followme")
}
#IBAction func logout(_ sender: AnyObject) {
delegate?.goToNextScene()
print("GOTOSCENE")
}
}
There is are no errors thrown but when I click/tap the button, nothing happens. It just prints "GOTOSCENE".
What I feel is
Your problem is right here
override func viewDidLoad() {
super.viewDidLoad()
let myCustomView = Bundle.main.loadNibNamed("ImageHeaderView", owner: self, options: nil)?[0] as! ImageHeaderView
myCustomView.delegate = self
}
I think you have added imageHeaderview from storyboard and in viewdidload you are creating new object of ImageHeaderView and assigning delegate to newly created object.
Try to outlet your ImageHeaderView and assign delegate to outleted object.
Hope this will fix your issue.
I have created a custom view from xib(freeform) in which there are two button (Login and cancel) and i have present it at a view according to some condition. Custom view get present on another view nicely but the button(Login an cancel) not getting any touch event.
Code of custom class and init method:
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
}
#IBAction func cancelButtonAction(sender: AnyObject) {
}
}
This is the block of code from where i have add the custom view as a subview.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if Reachability.isConnectedToNetwork() {
categoryObj = categoryArray .objectAtIndex(indexPath.row) as! TECategoryDetails
if categoryObj.categoryType == "premium" {
let screen = UIScreen.mainScreen().bounds
customView = customAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
else{
watchAllFlag = false
self.performSegueWithIdentifier("Episode", sender: self)
}
}
else {
self.showAlertPopUp()
}
}
You can also do like this way.
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
loginButton.addTarget(self, action: Selector(“loginButtonAction:”), forControlEvents: .TouchUpInside)
cancelButton.addTarget(self, action: Selector(“cancelButtonAction:”), forControlEvents: .TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
func loginButtonAction(sender: AnyObject) {
}
func cancelButtonAction(sender: AnyObject) {
}
}
Check it, its working:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func displayAlertBtnTapped(sender: AnyObject) {
let screen = UIScreen.mainScreen().bounds
let customView = CustomAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
}
CustomAlertView.swift:
import UIKit
class CustomAlertView: UIView {
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
print("Login button clicked");
}
#IBAction func cancelButtonAction(sender: AnyObject) {
print("Cancel button clicked");
}
}
For testing, use the following GitHub link:
https://github.com/k-sathireddy/AlertViewSample
I want to show my custom view when there is no network connection.
Something like this:
I have a ViewController inside a NavigationController
in AppDelegate I write like this:
var statusView: NetworkStatusView?
...
func showNetworkStatusView() {
if statusView == nil {
statusView = NetworkStatusView()
if let statusView = statusView {
let screenSize = UIScreen.mainScreen().bounds
statusView.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: 60)
statusView.hidden = false
if let rootViewController = window?.rootViewController {
rootViewController.view.addSubview(statusView)
}
}
}
}
and In my ViewController, I call like this:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.showNetworkStatusView()
But it doesn't show my custom view. I've also try view.addSubView(statusView) in my ViewController, but doesn't work also. I make sure that the function is called, because I debugged.
Here is my NetworkStatusView:
import UIKit
class NetworkStatusView: UIView {
#IBOutlet var contentView: UIView!
#IBOutlet weak var statusImageView: UIImageView!
#IBOutlet weak var statusLabel: UILabel!
required override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initSubviews()
}
func initSubviews() {
let nib = UINib(nibName: "NetworkStatusView", bundle: nil)
nib.instantiateWithOwner(self, options: nil)
contentView.frame = bounds
addSubview(contentView)
}
}