Although I could create a func setImages () in my CustomView class and call this after initializing myCustomView, I would like to understand if there's a cleaner way to set a view's delegate so that it is accessible when being initialized.
My main ViewController contains
class Main: UIViewController, CustomViewDelegate {
var imagesArray:[UIImage] = [Image1,Image2,Image3,Image4,Image5]
var myCustomView = CustomView()
override func viewDidLoad() {
super.viewDidLoad()
myCustomView.delegate = self
myCustomView = CustomView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
//this causes init of CustomView, but delegate is now nil and button images don't load
}
}
My CustomView file contains
var buttonsArray = [Button1,Button2,Button3,Button4,Button5]
override init(frame: CGRect) {
super.init(frame : frame)
for n in 0..< buttonsArray.count {
buttonsArray[n].setImage(delegate?.imagesArray[n], for: .normal)
}
}
You can create a new initializer which takes a frame and a delegate type and set the delegate before you set images to buttons
init(frame: CGRect,sender: CustomViewDelegate) {
super.init(frame : frame)
self.delegate = sender
for n in 0..< buttonsArray.count {
buttonsArray[n].setImage(delegate?.imagesArray[n], for: .normal)
}
}
For that, you have to confirm your viewController for the delegate(obviously).Call your customView like this in viewController:
class ViewController: UIViewController, CustomViewDelegate {
var myCustomView: CustomView!
override func viewDidLoad() {
myCustomView = CustomView(frame: self.view.bounds, sender: self)
}
}
hope it helps!
Related
I need to use custom views instead of views created with xib file.
How do I convert and use nib/xib file to programmatically view ?
class CustomCell: UITableViewCell {
var item: ViewModelItem? {
didSet {
titleLabel?.text = item?.title
}
}
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = .none
}
#IBOutlet weak var titleLabel: UILabel?
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
accessoryType = selected ? .checkmark : .none
}
}
I added it instead of xib. How should i send this?
I want the xib file to be programmatically added and controllable.
I want the xib file to be programmatically added and controllable.
class CustomCellView: UIView {
convenience init(frame: CGRect,checkboxTag:Int?) {
self.init(frame: frame)
self.addCustomView(checkboxTag: checkboxTag)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView(checkboxTag : Int?) {
var checkbox: UIButton = ClickingCheckbox()
if((checkboxTag) != nil)
{
checkbox.tag = checkboxTag!
}
self.addSubview(checkbox)
}
}
class ClickingCheckbox: UIButton {
convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
self.setImage(UIImage(named: "unfilled.png"), for: UIControlState.selected)
self.setImage(UIImage(named: "filled.png"), for: UIControlState.normal)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc private func buttonTapped() {
self.isSelected = !self.isSelected
}
}
When you are using view from Nib, it calls AwakeFromNib() method, custom views from code are using Init() methods.
To convert you Xib to programmatically code you need to setup all UI inside Init() method and move all initialConfiguration methods from AwakeFromNib() to Init()
I want to put all subview properties and my subview setup code in a UIView subclass and load that into my UIViewController subclass using loadView(). Then access the UIView subclass members without casting the view property of UIViewController all the time.
This is my UIView subclass AwesomeClass
class AwesomeView: UIView {
lazy var testView:UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
self.addSubview(view)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
testView.frame = CGRect(x: 10
, y: 10
, width: self.bounds.size.width - 20
, height: 100)
}
}
And my UIViewController subclass AwesomeViewController
class AwesomeViewController: UIViewController {
override func loadView() {
let view = AwesomeView()
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I could do something like:
var subclassedView:AwesomeView {
get {
return self.view as! AwesomeView
}
}
and
subclassedView.testView.backgroundColor = UIColor.blue
But is there a way to call testView directly with self.view in the AwesomeViewController?
Edit:
What I am looking for is Covariant return type in swift.
You can you something like this:
Instantiate an instance of AwesomeViewController in AwesomeView
class AwesomeView: UIView {
var exampleColorVariable:UIColor?
//here you instantiate your view controller
var awesomeViewController = AwesomeViewController()
lazy var testView:UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
self.addSubview(view)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
testView.frame = CGRect(x: 10
, y: 10
, width: self.bounds.size.width - 20
, height: 100)
}
}
then you can access any method in AwesomeView changing a little bit your code
class AwesomeViewController: UIViewController {
lazy var awesomeView: AwesomeView = {
let view = AwesomeView()
view.awesomeViewController = self
return view
}()
func setupView() {
view.addSubview(awesomeView)
// your constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupView()
// NOW YOU CAN ACCESS ANY METHOD IN YOUR VIEW awesomeView.yourFunction()
// or you access that variable
awesomeView.exampleColorVariable = .red // you can now omit UIColor in swift3
}
}
I have a custom UIView that I want to cover the screen once the user taps a button. It kind of simulates a custom view. There is child UIView in the custom UIView that should animate from the bottom (hidden at first) up to it's normal position (visible at the bottom). The problem that I am having is that it seems like layoutSubviews is a bad place to start doing animations. Where would the correct place be? Something like viewDidAppear but for UIViews.
In UIViewController:
let rect: CGRect = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height)
let alertView = AlertView(frame: rect)
view.addSubview(alertView)
In the AlertView:
import UIKit
class AlertView: UIView {
let nibName = "AlertView"
let animationDuration = 0.5
var view: UIView!
#IBOutlet weak var notificationView: UIView!
#IBOutlet weak var notificationBottomConstraint: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
viewSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
viewSetup()
}
override func didAddSubview(subview: UIView) {
super.didAddSubview(subview)
}
func viewSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// move the notification view offscreen
notificationBottomConstraint.constant = -notificationView.frame.size.height
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiateWithOwner(self, options: nil)[0] as! UIView
}
override func layoutSubviews() {
super.layoutSubviews()
print("layoutSubviews")
animate()
}
func animate() {
// move the notification up
self.notificationBottomConstraint.constant = 0
UIView.animateWithDuration(animationDuration) { () -> Void in
self.view.setNeedsDisplay()
}
}
}
I suggest you to call your animate() function from one of these methods:
willMoveToSuperview:
didMoveToSuperview
These methods of UIView as needed to track the movement of the current view in your view hierarchy.
Reference: UIView class
Your final constraint value is not in your animate closure. Try this:
func animate() {
// move the notification up
UIView.animateWithDuration(animationDuration) { () -> Void in
self.notificationBottomConstraint.constant = 0
self.view.setNeedsDisplay()
}
}
I have two classes and one of them I create a button which, I want to call a method in this class.
class blueFooterForImages: UIView{
//buttons for footer
let slideButton = UIButton()
let buttonOnFooter = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
//setting buttons
slideButton.frame = CGRectMake((self.frame.width / 2) - 10 , 10, 30, 30)
slideButton.addTarget(self, action: "animationFunction:", forControlEvents: UIControlEvents.TouchUpInside)
slideButton.setImage(imageForSlideButton,forState: .Normal)
self.addSubview(slideButton)}
}
internal func animationFunction(sender: UIButton!) {
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.frame.size.width -= 100
})
}
add this to your code, use singleton and send the instance
static var sharedInstance : blueFooterForImages?
override init(frame: CGRect) {
super.init(frame: frame)
blueFooterForImages.sharedInstance = self
//rest of init code....
}
in other class:
var button = UIButton(initParams...);
button.addTarget(blueFooterForImages.sharedInstance!,action:"animationFunction:", forControlEvents: UIControlEvents.TouchUpInside);
just make sure that blueFooterForImages.sharedInstance is not nil
(make sure that blueFooterForImages instance was created before you do this)
class FirstClass: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
SecondClass()
}
}
class TableView: FirstClass {
var bodyTableView1: UITableView!
override init() {
super.init(nibName: nil, bundle: nil)
bodyTableView1 = UITableView(frame: CGRectMake(0, 0, 250, 250 ))
bodyTableView1.backgroundColor = UIColor.whiteColor()
self.view.addSubview(bodyTableView1)
}
}
I've tried many ways but managed not to add anything from the second class.
If you could give me an example of the most basic is the appreciate.
Thank you!
Pls Modify Your TableView Like Below:
class TableView: UIView,UITableViewDataSource,UITableViewDelegate
{
var vc:UIViewController!
var bodyTableView1: UITableView!
func addActionBar(vc:UIViewController)
{
self.vc=vc;
bodyTableView1 = UITableView(frame: CGRectMake(0, 0, 250, 250 ))
bodyTableView1.backgroundColor = UIColor.whiteColor()
bodyTableView1.dataSource = self
bodyTableView1.delegate = self
vc.view.addSubview(bodyTableView1)
}
//Pls add tableview delegate methods here
}
And also add below code in FirstClass:
class FirstClass: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var ab : TableView = TableView(frame: CGRectMake(0, 0, 250, 250))
self.view.addSubview(ab)
ab.addActionBar(self)
}
}