I have created a custom UIView :
import UIKit
class IndicatorView: UIView {
var image_view_indicator: UIImageView!
var label_indicator: UILabel!
required init(coder decoder: NSCoder) {
super.init(coder: decoder)!
}
init(frame:CGRect, imageName: String, indicatorValue: String)
{
super.init(frame: frame)
self.frame = frame
image_view_indicator = UIImageView(frame: CGRect(x: 0, y: 0, width: 15, height: 15))
image_view_indicator.image = UIImage(named: imageName)
self.addSubview(image_view_indicator)
self.bringSubviewToFront(image_view_indicator)
label_indicator = UILabel(frame: CGRect(x: image_view_indicator.frame.size.width + 3, y: 0, width: 25, height: 15))
label_indicator.text = indicatorValue
label_indicator.textColor = UIColor.blackColor()
self.addSubview(label_indicator)
self.bringSubviewToFront(label_indicator)
}
}
This is my call from UIViewController :
view_indicator_friends = IndicatorView(frame: view_indicator_friends.frame, imageName: "friend.png", indicatorValue: "20")
I cross checked the IBOutlet connections. They seem to be fine.
But nothing is showing up in the custom view.
When you take your custom view from Xib through IBOutlet connection then your custom init will not invoked that why your image_view_indicator and label_indicator does not created. Thats why your custom view does not showing up properly. One solution is that implement your code under init(frame:CGRect, imageName: String, indicatorValue: String) method in the awakeFromNib method.
override func awakeFromNib() {
let frame = self.frame
image_view_indicator = UIImageView(frame: CGRect(x: 0, y: 0, width: 15, height: 15))
image_view_indicator.image = UIImage(named: imageName)
self.addSubview(image_view_indicator)
self.bringSubviewToFront(image_view_indicator)
label_indicator = UILabel(frame: CGRect(x: image_view_indicator.frame.size.width + 3, y: 0, width: 25, height: 15))
label_indicator.text = indicatorValue
label_indicator.textColor = UIColor.blackColor()
self.addSubview(label_indicator)
self.bringSubviewToFront(label_indicator)
}
Related
I'm trying to design such a button or a textfield, but exactly how can I do it? This is my textfield. I added an arrow to the right.
#IBOutlet weak var pickerTextField: UITextField!{
didSet {
pickerTextField.tintColor = UIColor.lightGray
pickerTextField.setIcon(#imageLiteral(resourceName: "drop-down-arrow"))
}
}
extension UITextField {
func setIcon(_ image: UIImage) {
let iconView = UIImageView(frame:
CGRect(x: -40, y: 7, width: 15, height: 15))
iconView.image = image
let iconContainerView: UIView = UIView(frame:
CGRect(x: -50, y: 0, width: 30, height: 30))
iconContainerView.addSubview(iconView)
rightView = iconContainerView
rightViewMode = .always
}
}
I would like to re-draw the line between two movable UIView, depending on the position of UIView.
So I found this. However, this method uses "Pan Gesture" to re-draw lines, depending on the position of the gesture.
Also found are setNeedsDisplay(), but this is a request to re-draw, not a real-time event function.
The way I want to find it is not to use gestures to redraw lines, but to re-draw lines in real time.
In a little bit more detail, I applied "UIColisionBehavior" to all the UIVviews I created. The UIView applied changes position as they are struck, and depending on the changed position, the line is being redrawn.
As if the UIView were moving in this way, the connected line was redrawn according to where it was moved:
Below is the code I'm experimenting with in the Playground. When you execute the code, you can see that the first connected purple line is connected to the falling UIView and does not fall off:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MoveAbleView : UIView {
var outGoingLine : CAShapeLayer?
var inComingLine : CAShapeLayer?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func lineTo(connectedView: MoveAbleView) -> CAShapeLayer {
let path = UIBezierPath()
path.move(to: self.center)
path.addLine(to: connectedView.center)
let line = CAShapeLayer()
line.path = path.cgPath
line.lineWidth = 5
line.strokeColor = UIColor.purple.cgColor
connectedView.inComingLine = line
outGoingLine = line
return line
}
}
class MyViewController : UIViewController {
var dynamicAnimator = UIDynamicAnimator()
var collisionBehavior = UICollisionBehavior()
var gravityBehavior = UIGravityBehavior()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
let viw = MoveAbleView(frame: CGRect(x: 100, y: 200, width: 50, height: 50))
viw.backgroundColor = UIColor.red
self.view.addSubview(viw)
let viw2 = MoveAbleView(frame: CGRect(x: 300, y: 100, width: 50, height: 50))
viw2.backgroundColor = UIColor.orange
self.view.addSubview(viw2)
let gravityViw = MoveAbleView(frame: CGRect(x: 100, y: 0, width: 50, height: 50))
gravityViw.backgroundColor = UIColor.green
self.view.addSubview(gravityViw)
let gravityViw2 = MoveAbleView(frame: CGRect(x: 300, y: -200, width: 50, height: 50))
gravityViw2.backgroundColor = UIColor.blue
self.view.addSubview(gravityViw2)
collisionBehavior.addItem(viw)
collisionBehavior.addItem(viw2)
collisionBehavior.addItem(gravityViw)
collisionBehavior.addItem(gravityViw2)
gravityBehavior.addItem(gravityViw)
gravityBehavior.addItem(gravityViw2)
dynamicAnimator.addBehavior(collisionBehavior)
dynamicAnimator.addBehavior(gravityBehavior)
self.view.layer.addSublayer(viw.lineTo(connectedView: viw2))
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
When UIView strikes and moves, how do you redraw a connected line in real time?
Actually, all what you need is another UIView to represent the lines and employ attachmentBehaviors. For instance, there is a line between two attached objects.
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
dynamicAnimator = UIDynamicAnimator(referenceView: view)
let viw = MoveAbleView(frame: CGRect(x: 100, y: 200, width: 50, height: 50))
viw.backgroundColor = UIColor.red
self.view.addSubview(viw)
let viw2 = MoveAbleView(frame: CGRect(x: 300, y: 200, width: 50, height: 50))
viw2.backgroundColor = UIColor.orange
self.view.addSubview(viw2)
let gravityViw = MoveAbleView(frame: CGRect(x: 100, y: 0, width: 50, height: 50))
gravityViw.backgroundColor = UIColor.green
self.view.addSubview(gravityViw)
let line1 = MoveAbleView(frame: CGRect(x: 125, y: 225, width: 200, height: 10))
line1.backgroundColor = UIColor.purple
self.view.addSubview(line1)
let l1 = UIAttachmentBehavior.init(item: viw, offsetFromCenter: UIOffset.zero, attachedTo: line1, offsetFromCenter: UIOffset.init(horizontal: -100, vertical: 0))
let l2 = UIAttachmentBehavior.init(item: viw2, offsetFromCenter: UIOffset.zero, attachedTo: line1, offsetFromCenter: UIOffset.init(horizontal: 100, vertical: 0))
collisionBehavior.addItem(viw)
collisionBehavior.addItem(viw2)
collisionBehavior.addItem(gravityViw)
gravityBehavior.addItem(gravityViw)
dynamicAnimator.addBehavior(l1)
dynamicAnimator.addBehavior(l2)
dynamicAnimator.addBehavior(collisionBehavior)
dynamicAnimator.addBehavior(gravityBehavior)
}
}
I have a custom Button with 2 Labels and Image as shown in below class
import UIKit
#IBDesignable
class CustomButton : UIButton {
let secondLine : UILabel = UILabel()
override func layoutSubviews() {
super.layoutSubviews()
// self.layer.cornerRadius = 10
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
self.layer.shadowOpacity = 1.0
self.layer.masksToBounds = false
}
#IBInspectable var rightLebelText : String?{
didSet {
updateView()
}
}
func updateView(){
if let mytext = rightLebelText {
let firstLine = UILabel(frame: CGRect(x: self.bounds.size.width - 210, y: 0, width: 200, height: 40))
firstLine.text = mytext
firstLine.textAlignment = .right
firstLine.font = UIFont.systemFont(ofSize: 20)
self.addSubview(firstLine)
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x: 5, y: 10, width: 20, height: 20))
imageView.image = UIImage(named:"arrow.png")
self.addSubview(imageView)
}
}
public func setSecondlabel(title : String){
secondLine.removeFromSuperview()
secondLine.frame = CGRect(x: 50, y: 0, width: 200, height: 40)
secondLine.text = title
secondLine.font = UIFont.boldSystemFont(ofSize: 20)
secondLine.removeFromSuperview()
self.addSubview(secondLine)
}
}
My issue is my view size is not updating on different devices when using
self.bounds.size.width
for the firstLine label as shown in below image its position should be on the custom button right edge
You need to override the layoutSubviews function have the frame of each element examine and update based on updated bounds of the custom view or assign proper layout constraints on each element while adding it.
If you are overriding the UIButton which has already a label and image property, you can use that one as well or create a custom class inherited from UIControl and create required three property as needed. I am adding an example of the custom class with image, title, and detail as shown in the problem.
class CustomButton : UIControl {
let imageView : UIImageView
let titleLabel : UILabel
let detailLabel : UILabel
fileprivate func setup() {
self.detailLabel.textAlignment = .right
self.detailLabel.font = UIFont.systemFont(ofSize: 20)
self.detailLabel.textColor = UIColor.black
self.titleLabel.font = UIFont.boldSystemFont(ofSize: 20)
self.titleLabel.textColor = UIColor.black
self.backgroundColor = UIColor.white
self.addSubview(self.imageView)
self.addSubview(self.titleLabel)
self.addSubview(self.detailLabel)
}
override init(frame: CGRect) {
self.imageView = UIImageView(frame: .zero)
self.titleLabel = UILabel(frame: .zero)
self.detailLabel = UILabel(frame: .zero)
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
self.imageView = UIImageView(frame: .zero)
self.titleLabel = UILabel(frame: .zero)
self.detailLabel = UILabel(frame: .zero)
super.init(coder: aDecoder)
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = CGRect(x: 5.0, y: self.bounds.midY - 10.0, width: 20.0, height: 20.0)
//You can make this width dynamic if you want to calculate width of text using self.detailLabel.text
var width : CGFloat = 200.0
self.titleLabel.frame = CGRect(x: self.imageView.frame.maxX + 5.0, y: self.bounds.minY, width: 200.0, height: self.bounds.height)
//Give the remaining space to the second label
width = self.bounds.width - (self.titleLabel.frame.maxX + 15.0)
self.detailLabel.frame = CGRect(x: self.titleLabel.frame.maxX + 5.0, y: self.bounds.minY, width: width, height: self.bounds.height)
}
}
I am unable to add a subclass to my parent UIView class. I am trying to build a BOOK class and have various UIView and UIImageView classes to build the covers and the pages. I get an error when adding the subclass to SELF. Would love some insight. PS - total swift noob
//book
class bookview : UIView {
var cover: UIView!
var backcover: UIView!
var page: UIImageView!
init (pages: Int) {
//backcover cover
backcover = UIView(frame: CGRect(x: 200, y: 200, width: bookwidth, height: bookheight))
backcover.backgroundColor = UIColor.blue
self.addSubview(backcover) //ERROR HERE
//pages
for i in 0 ..< pages {
page = UIImageView(frame: CGRect(x: bookwidth * i/10, y: bookheight * i/10, width: bookwidth, height: bookheight))
page.backgroundColor = UIColor.red
self.addSubview(page) //ERROR HERE
}
//front cover
cover = UIView(frame: CGRect(x: 0, y: 0, width: bookwidth, height: bookheight))
cover.backgroundColor = UIColor.blue
self.addSubview(cover) //ERROR HERE
super.init(frame: CGRect(x: 0, y: 0, width: bookwidth, height: bookheight))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//add book
let book = bookview(pages: 3)
The issue is that you can't call methods on self in the initializer until there is a self to call them on. There is no established value for self until you have called the superclass initializer. In other words, how does a subclass of UIView know how to "addSubview" when it has not yet been initialized as a UIView yet?
So, in your code example, just move the line:
super.init(frame: CGRect(x: 0, y: 0, width: bookwidth, height: bookheight))
to be before any time you call self.addSubview()
addSubview() is a method on UIView. UIView is your view's superclass. You cannot call methods on a superclass until it has been fully initialized.
To fix this, call super.init(frame:) earlier in your own init() function (before you call addSubview()).
I am lost.
I have a TableViewController that is filled programmatically from a collection. I need to show a form when the tableView is pulled down. Right now I have a InsertControl that contains two textFields.
InsertControl
class InsertControl: UIView {
//MARK: Properties
var name = ""
var quantity = 0
//MARK: Initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let nameTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 260, height: 44))
nameTextField.backgroundColor = UIColor.redColor()
let quantityTextField = UITextField(frame: CGRect(x: 270, y: 0, width: 60, height: 44))
quantityTextField.backgroundColor = UIColor.redColor()
addSubview(nameTextField)
addSubview(quantityTextField)
}
override func intrinsicContentSize() -> CGSize {
return CGSize(width: 350, height: 44)
}
}
then I found that I can put this control in the tableView header, so I have this code in my
tableViewController
let insertControl = InsertControl()
self.tableView.tableHeaderView = insertControl
self.tableView.contentOffset = CGPoint(x: 0, y: 44)
The problem is that I need to give to the InsertControl constructor a NSCoder which I don't have.
After I manage to get the form in the header, how can I pass a further swipe down to the control and make it add the content to the tableView collection?
I hope I was clear enough.
To answer your first question, in InsertControl, use override init(frame: CGRect) instead of required init?(coder aDecoder: NSCoder). It'll look like this:
override init(frame: CGRect) {
super.init(frame: frame)
let nameTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 260, height: 44))
nameTextField.backgroundColor = UIColor.redColor()
let quantityTextField = UITextField(frame: CGRect(x: 270, y: 0, width: 60, height: 44))
quantityTextField.backgroundColor = UIColor.redColor()
addSubview(nameTextField)
addSubview(quantityTextField)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func intrinsicContentSize() -> CGSize {
return CGSize(width: 350, height: 44)
}