Move UITextView to bottom of ViewController programmatically? - ios

I created the textView and Button(reply) programmatically and I want to move it down to the bottom of my ViewController. It's now being placed under the label(Joshyjosh) and it shouldn't do that. Is there something I need to add to my code or change so it can move to the bottom?
import UIKit
class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate {
var commentView: UITextView?
var footerView: UIView?
var contentHeight: CGFloat = 0
let FOOTERHEIGHT : CGFloat = 50;
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if self.footerView != nil {
return self.footerView!.bounds.height
}
return FOOTERHEIGHT
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: FOOTERHEIGHT))
footerView?.backgroundColor = UIColor(red: 243.0/255, green: 243.0/255, blue: 243.0/255, alpha: 1)
commentView = UITextView(frame: CGRect(x: 10, y: 5, width: tableView.bounds.width - 80 , height: 40))
commentView?.backgroundColor = UIColor.whiteColor()
commentView?.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
commentView?.layer.cornerRadius = 2
commentView?.scrollsToTop = true
footerView?.addSubview(commentView!)
let button = UIButton(frame: CGRect(x: tableView.bounds.width - 65, y: 10, width: 60 , height: 30))
button.setTitle("Reply", forState: UIControlState.Normal)
button.backgroundColor = UIColor(red: 155.0/255, green: 189.0/255, blue: 113.0/255, alpha: 1)
button.layer.cornerRadius = 5
button.addTarget(self, action: "reply", forControlEvents: UIControlEvents.TouchUpInside)
footerView?.addSubview(button)
commentView?.delegate = self
return footerView
}
func textViewDidChange(textView: UITextView) {
if (contentHeight == 0) {
contentHeight = commentView!.contentSize.height
}
if(commentView!.contentSize.height != contentHeight && commentView!.contentSize.height > footerView!.bounds.height) {
UIView.animateWithDuration(0.2, animations: { () -> Void in
let myview = self.footerView
print(self.commentView!.contentSize.height)
print(self.commentView?.font!.lineHeight)
let newHeight : CGFloat = self.commentView!.font!.lineHeight
let myFrame = CGRect(x: myview!.frame.minX, y: myview!.frame.minY - newHeight , width: myview!.bounds.width, height: newHeight + myview!.bounds.height)
myview?.frame = myFrame
let mycommview = self.commentView
let newCommHeight : CGFloat = self.commentView!.contentSize.height
let myCommFrame = CGRect(x: mycommview!.frame.minX, y: mycommview!.frame.minY, width: mycommview!.bounds.width, height: newCommHeight)
mycommview?.frame = myCommFrame
self.commentView = mycommview
self.footerView = myview
for item in self.footerView!.subviews {
if(item.isKindOfClass(UIButton.self)){
let button = item as! UIButton
let newY = self.footerView!.bounds.height / 2 - button.bounds.height / 2
let buttonFrame = CGRect(x: button.frame.minX, y: newY , width: button.bounds.width, height : button.bounds.height)
button.frame = buttonFrame
}
}
})
print(self.footerView?.frame)
print(self.commentView?.frame)
contentHeight = commentView!.contentSize.height
}
}

Related

Custom footerview not responding to my tap gesture recognizer label

So I've been at this for a few days and no luck. I have a a custom UIView that's made from a xib file and I am adding it to my footerView. The view is displayed but it is not responding to the gesture recognizer that I added to a label in the ViewController class. In the VC I create an instance of the UIView and added it to my tableView.
What's odd to is that when using the accessibility inspector it does read the labels
Here is the containerView
class AdviceCardWidgetContainerCurvedView: UIView {
struct Constants {
static let nibName = "ClariContainerView"
static let containerHeight: CGFloat = 169.0
static let curvedPercent: CGFloat = 0.2
}
let nibName = "ClariContainerView"
var clariView: UIView?
var clariTitle: String?
var clariQuestion: String?
#IBOutlet weak var clariTitleLabel: UILabel!
#IBOutlet weak var clariQuestionLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private func applyCurve(givenView view: UIView, curvedPercent: CGFloat) {
let shapeLayer = CAShapeLayer(layer: view.layer)
shapeLayer.path = self.pathForCurvedView(givenView: view, curvedPercent: curvedPercent).cgPath
shapeLayer.frame = view.bounds
view.layer.mask = shapeLayer
addSubview(view)
}
private func pathForCurvedView(givenView view: UIView, curvedPercent: CGFloat) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0.0, y: 0.0))
path.addLine(to: CGPoint(x: 0.0, y: view.bounds.size.height))
path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: view.bounds.size.height))
path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0.0))
path.addQuadCurve(to: CGPoint(x: 0, y: 0), controlPoint: CGPoint(x: UIScreen.main.bounds.width / 2, y: view.bounds.size.height * curvedPercent))
path.close()
return path
}
private func commonInit() {
guard let clariView = loadViewFromNib() else { return }
clariView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: containerHeight)
clariView.backgroundColor = .lightGray
applyCurve(givenView: clariView, curvedPercent: 0.1)
addSubview(clariView)
clariTitleLabel.text = "Ask TD Clari"
clariQuestionLabel.text = "What is my balance"
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: Constants.nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
And this is what's inside my view controller
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let curvedView = AdviceCardWidgetContainerCurvedView()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
curvedView.clariTitleLabel.accessibilityTraits = .button
curvedView.clariTitleLabel.isUserInteractionEnabled = true
curvedView.clariTitleLabel.backgroundColor = .red
curvedView.clariTitleLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(footerLableTapped)))
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 169))
tableView.tableFooterView?.addSubview(curvedView)
}
#objc func footerLableTapped() {
print("label tapped")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = "1"
return cell
}
}
Alright, so I solved this problem after a week of trying. In the end adding a custom xib file to a footerView causes some errors and conflicts with autoLayout. Everything looks like its supposed to be, but the frames are essentially non existent for your added subviews like buttons and label and that's why they can't be tapped. Make sure you have a reference to your tableView from storyboard or how ever you created it.
override func viewDidLoad() {
super.viewDidLoad()
let remainingBottomFooterSpace = remaingBottomFooterViewSpace(for: tableView)
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 169))
footerView.backgroundColor = .clear
applyCurve(givenView: footerView, curvedPercent: 0.04)
let remainingFooterView = UIView(frame: CGRect(x: 0, y: 169, width: tableView.frame.size.width, height: remainingBottomFooterSpace))
remainingFooterView.backgroundColor = .lightGray
let curve = UIView()
curve.translatesAutoresizingMaskIntoConstraints = false
curve.backgroundColor = .lightGray
let icon = UIImageView()
icon.translatesAutoresizingMaskIntoConstraints = false
icon.image = UIImage(named: "mytd_clari")
icon.contentMode = .scaleAspectFill
curved.addSubview(icon)
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.isUserInteractionEnabled = true
button.setTitle("Ask", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 16.0, weight: .medium)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(footerLableTapped), for: .touchUpInside)
let questionLabel = UILabel()
questionLabel.translatesAutoresizingMaskIntoConstraints = false
questionLabel.text = "What is my balance"
questionLabel.textColor = .green
questionLabel.font = .systemFont(ofSize: 13, weight: .regular)
questionLabel.textAlignment = .center
curve.addSubview(clariQuestionLabel)
let buttonContainer = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: 169))
curve.addSubview(buttonContainer)
buttonContainer.addSubview(button)
tableView.tableFooterView = footerView
tableView.tableFooterView?.addSubview(remainingFooterView)
tableView.tableFooterView?.addSubview(curve)
NSLayoutConstraint.activate([
footerView.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
footerView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor)
])
NSLayoutConstraint.activate([
curve.widthAnchor.constraint(equalToConstant: tableView.frame.size.width),
curve.heightAnchor.constraint(equalToConstant: 169)
])
NSLayoutConstraint.activate([
icon.topAnchor.constraint(equalTo: curve.topAnchor, constant: 39),
icon.widthAnchor.constraint(equalToConstant: 40),
icon.heightAnchor.constraint(equalToConstant: 40),
icon.centerXAnchor.constraint(equalTo: curve.centerXAnchor),
])
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: icon.bottomAnchor),
button.centerXAnchor.constraint(equalTo: icon.centerXAnchor)
])
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: button.bottomAnchor),
label.centerXAnchor.constraint(equalTo: icon.centerXAnchor),
])
}
If you want to add the curve here are the methods:
func applyCurve(givenView view: UIView, curvedPercent: CGFloat) {
let shapeLayer = CAShapeLayer(layer: view.layer)
shapeLayer.path = self.pathForCurvedView(curvedPercent: curvedPercent).cgPath
shapeLayer.frame = view.bounds
view.layer.mask = shapeLayer
}
func pathForCurvedView(curvedPercent: CGFloat) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0.0, y: 0.0))
path.addLine(to: CGPoint(x: 0.0, y: UIScreen.main.bounds.height))
path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: UIScreen.main.bounds.height))
path.addLine(to: CGPoint(x: UIScreen.main.bounds.width, y: 0.0))
path.addQuadCurve(to: CGPoint(x: 0, y: 0), controlPoint: CGPoint(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height * curvedPercent))
path.close()
return path
}
and if you want to add the remaining footerView space, here is the func
func remaingBottomFooterViewSpace(for tableView: UITableView) -> CGFloat {
//Get content height & calculate new footer height
let cells = tableView.visibleCells
var height: CGFloat = 0
for i in 0..<cells.count {
height += cells[i].frame.height
}
height = tableView.bounds.height - ceil(height)
//If theh footer new height is negative, we make it 0 since we don't need extra footer view anymore
height = height > 0 ? height : 0
return height
}

Changing views causes things on screen to appear

Right now, I have a custom graph class which creates bar charts and displays them. However they only appear after I appear on the view controller twice. For eg. here I am on one of the view controllers that has the graph but it shows in an incomplete manner.
Then here I am at the same view controller but with the graph how it is meant to look like. As you can see, the bars have gotten longer and the dashed lines have appeared.
To achieve this, all I did was click on one of the tabs in the bottom and then clicked back on the tab for report and it changed the view. I really have no idea why this is happening and have been trying to tackle this for 2 days now. If someone can help me it would be great. Here is the code for a sample viewcontroller that shows the graph.
override func viewDidLoad() {
self.tabBarController?.tabBar.barTintColor = UIColor(red:0.18, green:0.21, blue:0.25, alpha:1.0)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
self.tabBarController?.tabBar.barTintColor = UIColor(red:0.18, green:0.21, blue:0.25, alpha:1.0)
tupleArray.removeAll()
newTuple.removeAll()
filteredCategories.removeAll()
categories.removeAll()
self.categories = CoreDataHelper.retrieveCategories()
tableView.tableFooterView = UIView(frame: .zero)
tableView.tableFooterView?.isHidden = true
tableView.backgroundColor = UIColor.clear
tableView.layoutMargins = UIEdgeInsets.zero
tableView.separatorInset = UIEdgeInsets.zero
tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
UIColor(red:0.40, green:0.43, blue:0.48, alpha:1.0)
currentYear1 = Calendar.current.date(byAdding: .year, value: -1, to: Date())!
currentYear = String(describing: Calendar.current.component(.year, from: currentYear1))
yearLabel.text = "\(currentYear)"
if ExpensesAdditions().yearHasExpense(year: currentYear){
noExpenseLabel.isHidden = true
}
else{
tableView.isHidden = true
barChartView.isHidden = true
noExpenseLabel.isHidden = false
totalSpentLabel.isHidden = true
}
totalSpent = ExpensesAdditions().retrieveYearlySum(year:currentYear)
totalSpentLabel.text = "Total Spent: " + ExpensesAdditions().convertToMoney(totalSpent)
for category in categories{
if ExpensesAdditions().categoryinYearHasExpense(year:currentYear,category:category.title!){
filteredCategories.append(category)
tupleArray.append((category.title!,ExpensesAdditions().retrieveCategoryExpenseForYear(category: category.title!, year: currentYear)))
}
else{}
}
newTuple = tupleArray.sorted(by: { $0.1 > $1.1 })
if ExpensesAdditions().yearHasExpense(year: currentYear){
let dataEntries = generateDataEntries()
barChartView.dataEntries = dataEntries
}
}
override func viewDidAppear(_ animated: Bool) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredCategories.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "lastYearAnalysisCell") as! LastYearAnalysisViewTableViewCell
cell.isUserInteractionEnabled = false
let row = indexPath.row
let percentage:Double = (newTuple[row].1/totalSpent)*100
let percentageDisplay:Int = Int(percentage.rounded())
cell.nameLabel.text = newTuple[row].0
cell.amountLabel.text = "(\(percentageDisplay)"+"%) "+String(describing: UserDefaults.standard.value(forKey: "chosenCurrencySymbol")!)+ExpensesAdditions().convertToMoney(newTuple[row].1)
return cell
}
func generateDataEntries() -> [BarEntry] {
let colors = [#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1), #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1), #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1), #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1), #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)]
maximum = newTuple[0].1
var result: [BarEntry] = []
/// ---- Complicated Divising -------//////
var maximumString:String = ExpensesAdditions().convertToMoney(maximum)
var maximumInt:Int = Int(maximumString.getAcronyms())!
let endIndex = maximumString.index(maximumString.endIndex, offsetBy: -3)
let truncated = maximumString.substring(to: endIndex)
if maximumInt < 5{
divisor = Double((5*(pow(10, truncated.count - 1))) as NSNumber)
}
else if maximumInt > 5{
divisor = Double((pow(10, truncated.count)) as NSNumber)
}
for i in 0..<filteredCategories.count {
let value = ExpensesAdditions().convertToMoney(tupleArray[i].1)
var height:Double = Double(value)! / divisor
result.append(BarEntry(color: colors[i % colors.count], height: height, textValue: value, title: filteredCategories[i].title!))
}
return result
//// --- Complicated Divising End -------- /////
}
If you need anymore code, please let me know and thanks in advance!
Here is the code for the bar chart entry code:
import UIKit
class BasicBarChart: UIView {
/// the width of each bar
let barWidth: CGFloat = 40.0
/// space between each bar
let space: CGFloat = 20.0
/// space at the bottom of the bar to show the title
private let bottomSpace: CGFloat = 40.0
/// space at the top of each bar to show the value
private let topSpace: CGFloat = 40.0
/// contain all layers of the chart
private let mainLayer: CALayer = CALayer()
/// contain mainLayer to support scrolling
private let scrollView: UIScrollView = UIScrollView()
var dataEntries: [BarEntry]? = nil {
didSet {
mainLayer.sublayers?.forEach({$0.removeFromSuperlayer()})
if let dataEntries = dataEntries {
scrollView.contentSize = CGSize(width: (barWidth + space)*CGFloat(dataEntries.count), height: self.frame.size.height)
mainLayer.frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)
drawHorizontalLines()
for i in 0..<dataEntries.count {
showEntry(index: i, entry: dataEntries[i])
}
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
convenience init() {
self.init(frame: CGRect.zero)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
scrollView.layer.addSublayer(mainLayer)
self.addSubview(scrollView)
}
override func layoutSubviews() {
scrollView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
}
private func showEntry(index: Int, entry: BarEntry) {
/// Starting x postion of the bar
let xPos: CGFloat = space + CGFloat(index) * (barWidth + space)
/// Starting y postion of the bar
let yPos: CGFloat = translateHeightValueToYPosition(value: Float(entry.height))
drawBar(xPos: xPos, yPos: yPos, color: entry.color)
/// Draw text above the bar
drawTextValue(xPos: xPos - space/2, yPos: yPos - 30, textValue: entry.textValue, color: entry.color)
/// Draw text below the bar
drawTitle(xPos: xPos - space/2, yPos: mainLayer.frame.height - bottomSpace + 10, title: entry.title, color: entry.color)
}
private func drawBar(xPos: CGFloat, yPos: CGFloat, color: UIColor) {
let barLayer = CALayer()
barLayer.frame = CGRect(x: xPos, y: yPos, width: barWidth, height: mainLayer.frame.height - bottomSpace - yPos)
barLayer.backgroundColor = color.cgColor
mainLayer.addSublayer(barLayer)
}
private func drawHorizontalLines() {
self.layer.sublayers?.forEach({
if $0 is CAShapeLayer {
$0.removeFromSuperlayer()
}
})
let horizontalLineInfos = [["value": Float(0.0), "dashed": true], ["value": Float(0.5), "dashed": true], ["value": Float(1.0), "dashed": true]]
for lineInfo in horizontalLineInfos {
let xPos = CGFloat(0.0)
let yPos = translateHeightValueToYPosition(value: (lineInfo["value"] as! Float))
let path = UIBezierPath()
path.move(to: CGPoint(x: xPos, y: yPos))
path.addLine(to: CGPoint(x: scrollView.frame.size.width, y: yPos))
let lineLayer = CAShapeLayer()
lineLayer.path = path.cgPath
lineLayer.lineWidth = 0.5
if lineInfo["dashed"] as! Bool {
lineLayer.lineDashPattern = [4, 4]
}
lineLayer.strokeColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1).cgColor
self.layer.insertSublayer(lineLayer, at: 0)
}
}
private func drawTextValue(xPos: CGFloat, yPos: CGFloat, textValue: String, color: UIColor) {
let textLayer = CATextLayer()
textLayer.frame = CGRect(x: xPos, y: yPos, width: barWidth+space, height: 22)
textLayer.foregroundColor = color.cgColor
textLayer.backgroundColor = UIColor.clear.cgColor
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
textLayer.font = CTFontCreateWithName(UIFont.systemFont(ofSize: 0).fontName as CFString, 0, nil)
textLayer.fontSize = 14
textLayer.string = textValue
mainLayer.addSublayer(textLayer)
}
private func drawTitle(xPos: CGFloat, yPos: CGFloat, title: String, color: UIColor) {
let textLayer = CATextLayer()
textLayer.frame = CGRect(x: xPos, y: yPos, width: barWidth + space, height: 22)
textLayer.foregroundColor = color.cgColor
textLayer.backgroundColor = UIColor.clear.cgColor
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
textLayer.font = CTFontCreateWithName(UIFont.systemFont(ofSize: 0).fontName as CFString, 0, nil)
textLayer.fontSize = 14
textLayer.string = title
mainLayer.addSublayer(textLayer)
}
private func translateHeightValueToYPosition(value: Float) -> CGFloat {
let height: CGFloat = CGFloat(value) * (mainLayer.frame.height - bottomSpace - topSpace)
return mainLayer.frame.height - bottomSpace - height
}
}
The problem is most likely that you set up your bar chart in viewWillAppear, at which point the final size of the view has not been set yet. To fix this you must either delay setting the data until in viewDidAppear, or you need to trigger a redraw of the bars and dashed lines when the frame size has changed i.e. from layoutSubviews.
One point of advice I want to share with you is that you should try to separate your code so that sizing and positioning of all the view's sub-items are done in layoutSubviews, and the actual adding and removal of them are done elsewhere.
Update:
In your class BasicBarChart you should try to separate adding the chart elements, and do the actual sizing of the elements. This is because sizing is an event that often occurs more than once, especially when using auto-layout.
If your BasicBarChart view is set up with constraints, it will usually receive at least two different sizes during setup, once with the sizes in your storyboard file, and once with the actual device derived sizes. Since you don't want to add everything more than once, you should do the adding elsewhere. A good place could be during initialization or when setting data.
The sizing of a view's sub-elements is best done in its layoutSubviews() function. You have already started! Just move over the sizing of your other elements here too, and everything should work much better.
class BasicBarChart: UIView {
override func layoutSubviews() {
scrollView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
// Size and position bars, labels and dashed lines here
}
}

How to make image weight and height fill screen in Swift Xcode?

I found a code to make slide in swift, but cant find, how to make the IMAGE fill the whole screen.
Could you help?
here is the screenshot of slider, and you will see the anchors I placed on it to show you, the whole screen.
and here is the code of it;
import UIKit
class OnboardingController: UIViewController, UIScrollViewDelegate {
let backgroundColor = UIColor(red: 241.0/255.0, green: 196.0/255.0, blue: 15.0/255.0, alpha: 1.0)
let slides = [
[ "image": "book4page1.png"],
[ "image": "book4page2.png"],
[ "image": "book4page3.png"],
]
let screen: CGRect = UIScreen.mainScreen().bounds
var scroll: UIScrollView?
var dots: UIPageControl?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = backgroundColor
scroll = UIScrollView(frame: CGRect(x: 0.0, y: 0.0, width: screen.width, height: screen.height * 0.9))
scroll?.showsHorizontalScrollIndicator = false
scroll?.showsVerticalScrollIndicator = false
scroll?.pagingEnabled = true
view.addSubview(scroll!)
if (slides.count > 1) {
dots = UIPageControl(frame: CGRect(x: 0.0, y: screen.height * 0.875, width: screen.width, height: screen.height * 0.05))
dots?.numberOfPages = slides.count
view.addSubview(dots!)
}
for var i = 0; i < slides.count; ++i {
if let image = UIImage(named: slides[i]["image"]!) {
let imageView: UIImageView = UIImageView(frame: getFrame(image.size.width, iH: image.size.height, slide: i, offset: screen.height * 0.15))
imageView.image = image
scroll?.addSubview(imageView)
}
if let text = slides[i]["text"] {
let textView = UITextView(frame: CGRect(x: screen.width * 0.05 + CGFloat(i) * screen.width, y: screen.height * 0.745, width: screen.width * 0.9, height: 100.0))
textView.text = text
textView.editable = false
textView.selectable = false
textView.textAlignment = NSTextAlignment.Center
textView.font = UIFont.systemFontOfSize(20, weight: 0)
textView.textColor = UIColor.whiteColor()
textView.backgroundColor = UIColor.clearColor()
scroll?.addSubview(textView)
}
}
scroll?.contentSize = CGSizeMake(CGFloat(Int(screen.width) * slides.count), screen.height * 0.5)
scroll?.delegate = self
dots?.addTarget(self, action: Selector("swipe:"), forControlEvents: UIControlEvents.ValueChanged)
let closeButton = UIButton()
closeButton.frame = CGRect(x: screen.width - 70, y: 20, width: 60, height: 60)
closeButton.setTitle("Skip", forState: .Normal)
closeButton.setTitleColor(UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 0.5), forState: .Normal)
closeButton.titleLabel!.font = UIFont.systemFontOfSize(16)
closeButton.addTarget(self, action: "pressed:", forControlEvents: .TouchUpInside)
view.addSubview(closeButton)
}
func pressed(sender: UIButton!) {
self.dismissViewControllerAnimated(true) { () -> Void in
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getFrame (iW: CGFloat, iH: CGFloat, slide: Int, offset: CGFloat) -> CGRect {
let mH: CGFloat = screen.height * 0.50
let mW: CGFloat = screen.width
var h: CGFloat
var w: CGFloat
let r = iW / iH
if (r <= 1) {
h = min(mH, iH)
w = h * r
} else {
w = min(mW, iW)
h = w / r
}
return CGRectMake(
max(0, (mW - w) / 2) + CGFloat(slide) * screen.width,
max(0, (mH - h) / 2) + offset,
w,
h
)
}
func swipe(sender: AnyObject) -> () {
if let scrollView = scroll {
let x = CGFloat(dots!.currentPage) * scrollView.frame.size.width
scroll?.setContentOffset(CGPointMake(x, 0), animated: true)
}
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) -> () {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
dots!.currentPage = Int(pageNumber)
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
}
On your imageView set imageView.contentMode = UIViewContentMode.ScaleAspectFit
Depending on how you want it to scale you should modify the contentMode
of the UIImageView's.
In Objective-C you would do this (it'll be something similar in Swift):
UIImageView * iv = [UIImageView new];
iv.frame = scrollView.bounds;
iv.contentMode = UIViewContentModeScaleAspectFill;
iv.clipsToBounds = true;
iv.image = [UIImage imageNamed:#"image.jpg"];
[scrollView addSubview:iv];
The contentMode is the line you're looking for.

UITableView cell height for iOS 7.1.2

I'm trying to adapt the height of the cells of a UITableView in swift programmatically for iOS 7.1.2 (sadly got asked for it.). There are no issues for all iOS versions after 7 but as it is the UITableView displays with a height of 1..
Here is my code (I made the interface programmatically as I literally HATE the design interface of Xcode and don't use AutoLayout).
Any ideas?
import UIKit
class ChemieListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
private var imageView = UIImageView ()
private var bg_image = UIImage()
private var titre = UILabel()
private var button_Back = UIButton()
var navigationBar = UIView()
var items:[String] = ["1","A","B","C","D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
var lbl_suche_by_txt = UILabel()
var text_search = UITextField()
var alph_list = UITableView()
var lbl_such_by_alph = UILabel()
var scroll: UIScrollView!
var scroll_h: CGFloat = CGFloat(0)
private var waitView = UIView()
private var loading_view = UIImageView()
private var loading_text = UILabel()
private var has_started = false
private var bg_infro = UIView()
private var txt_info = UILabel()
private var options_pics = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
//---------------------Scroll View-----------------------------
self.scroll = UIScrollView()
scroll_h = 0
//----------------------Wait screen---------------------------
waitView.backgroundColor = UIColor.blackColor()
waitView.alpha = 0.8
let ScreenSize: CGRect = UIScreen.mainScreen().bounds
loading_text.text = NSLocalizedString("wait", comment: " ")
loading_text.textColor = UIColor(white: 1, alpha: 1)
loading_text.textAlignment = .Center
loading_text.backgroundColor = UIColor(white: 1, alpha: 0)
//----------------------Navigation Bar-------------------------
navigationBar.backgroundColor = GetColorFromHex(0x2139D2)
//----------------------Back Button----------------------------
var back_img: UIImage? = UIImage(named: "back")
if (back_img == nil){
back_img = UIImage(named: "back.png")
}
button_Back.translatesAutoresizingMaskIntoConstraints = false
button_Back.addTarget(self, action: #selector(ProduktViewController.button_back_Pressed), forControlEvents: .TouchDown)
button_Back.setBackgroundImage(back_img, forState: UIControlState.Normal)
button_Back.contentMode = UIViewContentMode.ScaleAspectFit
self.view.addSubview(button_Back)
//----------------------Background Image-----------------------
//Background Image
var BGImage: UIImage? = UIImage(named: "background")
if(BGImage == nil){
BGImage = UIImage(named: "background.jpg")
}
bg_image = BGImage!
imageView = UIImageView(frame: self.view.bounds)
imageView.image = bg_image
imageView.clipsToBounds = true
self.view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
//------------------------Title------------------------------------
let largeur_title = ScreenSize.width - button_Back.frame.width - 30
titre.adjustsFontSizeToFitWidth = true
titre.text = NSLocalizedString("liste", comment: " ")
titre.textColor = UIColor.whiteColor()
titre.frame = CGRect (x: button_Back.frame.origin.x + button_Back.frame.width + 10, y: button_Back.frame.origin.y, width: largeur_title, height: 50)
titre.textAlignment = .Center
//---------------------txt For input search-----------------------
lbl_suche_by_txt.text = NSLocalizedString("search_field", comment: "")
lbl_suche_by_txt.textAlignment = .Center
lbl_suche_by_txt.backgroundColor = UIColor(white: 1, alpha: 0.5)
//---------------------TextField input---------------------------
text_search.delegate = self
text_search.resignFirstResponder()
text_search.textAlignment = .Center
text_search.backgroundColor = UIColor.whiteColor()
text_search.placeholder = NSLocalizedString("search_here", comment: "")
text_search.keyboardType = UIKeyboardType.Default
text_search.returnKeyType = UIReturnKeyType.Done
//---------------------txt For alphabetical search-----------------------
lbl_such_by_alph.text = NSLocalizedString("search_list", comment: "")
lbl_such_by_alph.textAlignment = .Center
lbl_such_by_alph.backgroundColor = UIColor(white: 1, alpha: 0.5)
//---------------------Table View Alphabet-------------------------------
alph_list.delegate = self
alph_list.dataSource = self
alph_list.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
alph_list.estimatedRowHeight = 50.0
alph_list.rowHeight = UITableViewAutomaticDimension
//---------------------BG Info Rights------------------------------------
bg_infro.backgroundColor = UIColor(white: 1, alpha: 0.5)
txt_info.text = NSLocalizedString("rights", comment: "")
txt_info.numberOfLines = 0
txt_info.textColor = UIColor.blackColor()
let orient = UIApplication.sharedApplication().statusBarOrientation
switch orient{
case .Portrait:
self.setContstraintsPortrait()
break
default:
self.setContstraintsLandscape()
break
}
navigationBar.addSubview(button_Back)
navigationBar.addSubview(titre)
self.scroll.addSubview(lbl_suche_by_txt)
self.scroll.addSubview(text_search)
self.scroll.addSubview(lbl_such_by_alph)
self.scroll.addSubview(alph_list)
self.scroll.addSubview(bg_infro)
self.scroll.addSubview(txt_info)
waitView.addSubview(loading_text)
waitView.hidden = true
self.scroll.addSubview(waitView)
self.view.addSubview(scroll)
self.view.addSubview(navigationBar)
}
override func viewDidAppear(animated: Bool) {
alph_list.reloadData()
var table_height:CGFloat = 0
//----------------Init Values----------------------
let ScreenSize: CGRect = UIScreen.mainScreen().bounds
let w = ScreenSize.width
for index in 0...items.count - 1 {
let IndexPath = NSIndexPath(forRow:index, inSection:0)
let cell = alph_list.cellForRowAtIndexPath(IndexPath)
if cell != nil {
let cell: UITableViewCell = alph_list.cellForRowAtIndexPath(IndexPath)!
cell.textLabel?.lineBreakMode = .ByWordWrapping
cell.textLabel?.numberOfLines = 0
print(cell.textLabel?.text)
alph_list.endUpdates()
table_height += alph_list.cellForRowAtIndexPath(IndexPath)!.frame.height
print(table_height)
if #available(iOS 8, *){
table_height += alph_list.cellForRowAtIndexPath(IndexPath)!.frame.height
}else{
print(table_height)
}
}
}
alph_list.frame = CGRect (x: button_Back.frame.origin.x, y: lbl_such_by_alph.frame.origin.y + lbl_such_by_alph.frame.height + 10, width: w - 20 , height: 26*45)
alph_list.contentSize = CGSizeMake(200, (26*45))
//-------------BG info rights--------------------------
bg_infro.frame = CGRect(x: button_Back.frame.origin.x, y: alph_list.frame.origin.y + alph_list.frame.height + 10 , width: w - 20, height: 220)
//-------------BG txt rights--------------------------
txt_info.frame = CGRect(x: button_Back.frame.origin.x + 10, y: bg_infro.frame.origin.y + 10 , width: w - 40, height: 250)
scroll_h = bg_infro.frame.origin.y + bg_infro.frame.height + 30
self.scroll.contentSize = CGSizeMake(w, scroll_h)
has_started = true
}
func setContstraintsLandscape(){
print("portrait func beständigkeitsliste")
//----------------Scroll View-----------------------
scroll.frame = UIScreen.mainScreen().bounds
//----------------Init Values-----------------------
let ScreenSize: CGRect = UIScreen.mainScreen().bounds
let w = ScreenSize.width
let h = ScreenSize.height
let zero: CGFloat = 0
//-------------Background---------------------------
imageView.removeFromSuperview()
imageView.translatesAutoresizingMaskIntoConstraints = true
imageView.frame = CGRectMake(zero,zero, w, h)
imageView.image = bg_image
self.view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
//---------------Navigation Bar--------------------
navigationBar.frame = CGRect(x: 0, y: 0, width: w, height: 60)
//--------------Button Back-------------------------
button_Back.translatesAutoresizingMaskIntoConstraints = true
button_Back.frame = CGRectMake(10, 10, 50, 50)
//--------------Title-------------------------------
titre.frame = CGRect (x: 0, y: button_Back.frame.origin.y, width: w, height: 50)
//-------------Text Search by Text------------------
lbl_suche_by_txt.frame = CGRect(x: button_Back.frame.origin.x, y: button_Back.frame.origin.y + button_Back.frame.height + 10 , width: w - 20, height: 40)
//-------------Text Field Search by Text------------------
text_search.frame = CGRect(x: button_Back.frame.origin.x, y: lbl_suche_by_txt.frame.origin.y + lbl_suche_by_txt.frame.height + 10 , width: w - 20, height: 40)
//-------------Text Search by Alphabet------------------
lbl_such_by_alph.frame = CGRect(x: button_Back.frame.origin.x, y: text_search.frame.origin.y + text_search.frame.height + 30 , width: w - 20, height: 40)
//-------------List Alphabet------------------
var table_height: CGFloat = 0
if(has_started == false){
table_height = CGFloat(items.count * 50)
}else{
for index in 0...items.count - 1 {
let IndexPath = NSIndexPath(forRow:index, inSection:0)
let cell = alph_list.cellForRowAtIndexPath(IndexPath)
if cell != nil {
table_height += alph_list.cellForRowAtIndexPath(IndexPath)!.frame.height
}
}
}
alph_list.frame = CGRect(x: button_Back.frame.origin.x, y: lbl_such_by_alph.frame.origin.y + lbl_such_by_alph.frame.height + 10 , width: w - 20, height: table_height)
//-------------BG info rights--------------------------
bg_infro.frame = CGRect(x: button_Back.frame.origin.x, y: alph_list.frame.origin.y + alph_list.frame.height + 10 , width: w - 20, height: 220)
//-------------BG txt rights--------------------------
txt_info.frame = CGRect(x: button_Back.frame.origin.x + 10, y: bg_infro.frame.origin.y + 20 , width: w - 40, height: 250)
//-------------Scroll View Size-------------------------------
scroll_h = alph_list.frame.origin.y + table_height + 30
self.scroll.contentSize = CGSizeMake(ScreenSize.width, scroll_h)
//----------------Wait Screen-----------------------
waitView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.scroll.frame.height)
loading_text.frame = CGRect(x: (ScreenSize.width - 150) / 2, y: (ScreenSize.height - 100) / 2, width: 150, height: 100)
}
func setContstraintsPortrait(){
print("portrait func liste chemie")
//----------------Scroll View-----------------------
scroll.frame = UIScreen.mainScreen().bounds
//----------------Init Values-----------------------
let ScreenSize: CGRect = UIScreen.mainScreen().bounds
let w = ScreenSize.width
let h = ScreenSize.height
let zero: CGFloat = 0
//--------------------------------------------------
imageView.removeFromSuperview()
imageView.translatesAutoresizingMaskIntoConstraints = true
imageView.frame = CGRectMake(zero,zero, w, h)
imageView.image = bg_image
self.view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
//---------------Navigation Bar---------------------
navigationBar.frame = CGRect(x: 0, y: 0, width: w, height: 80)
//--------------Button Back-------------------------
button_Back.translatesAutoresizingMaskIntoConstraints = true
button_Back.frame = CGRectMake(10, 30, 50, 50)
//--------------Title-------------------------------
titre.frame = CGRect (x: 0, y: button_Back.frame.origin.y, width: w, height: 50)
//-------------Text Search by Text------------------
lbl_suche_by_txt.frame = CGRect(x: button_Back.frame.origin.x, y: button_Back.frame.origin.y + button_Back.frame.height + 10 , width: w - 20, height: 40)
//-------------Text Field Search by Text------------------
text_search.frame = CGRect(x: button_Back.frame.origin.x, y: lbl_suche_by_txt.frame.origin.y + lbl_suche_by_txt.frame.height + 10 , width: w - 20, height: 40)
//-------------Text Search by Alphabet------------------
lbl_such_by_alph.frame = CGRect(x: button_Back.frame.origin.x, y: text_search.frame.origin.y + text_search.frame.height + 30 , width: w - 20, height: 40)
//-------------List Alphabet------------------
var table_height: CGFloat = 0
if(has_started == false){
table_height = CGFloat(items.count * 50)
}else{
for index in 0...items.count - 1 {
let IndexPath = NSIndexPath(forRow:index, inSection:0)
let cell = alph_list.cellForRowAtIndexPath(IndexPath)
if cell != nil {
table_height += alph_list.cellForRowAtIndexPath(IndexPath)!.frame.height
}
}
}
alph_list.frame = CGRect(x: button_Back.frame.origin.x, y: lbl_such_by_alph.frame.origin.y + lbl_such_by_alph.frame.height + 10 , width: w - 20, height: table_height)
alph_list.contentSize = CGSizeMake(w-20, table_height)
print(table_height)
//-------------BG info rights--------------------------
bg_infro.frame = CGRect(x: button_Back.frame.origin.x, y: alph_list.frame.origin.y + alph_list.frame.height + 10 , width: w - 20, height: 220)
//-------------BG txt rights--------------------------
txt_info.frame = CGRect(x: button_Back.frame.origin.x + 10, y: bg_infro.frame.origin.y + 20 , width: w - 40, height: 250)
//-------------Scroll View Size-------------------------------
scroll_h = alph_list.frame.origin.y + table_height + 30
self.scroll.contentSize = CGSizeMake(w, scroll_h)
//----------------Wait Screen-----------------------
waitView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.scroll.frame.height)
loading_text.frame = CGRect(x: (w - 150) / 2, y: (h - 100) / 2, width: 150, height: 100)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
text_search.resignFirstResponder()
print("Oki")
let listresultview: ListResultsViewController = ListResultsViewController(imageURL: text_search.text)
self.presentViewController(listresultview, animated:true, completion: nil)
return true
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
waitView.frame = CGRect(x: 0, y: scroll.bounds.origin.y, width: self.view.frame.width, height: self.scroll.frame.height)
loading_text.frame = CGRect(x: (UIScreen.mainScreen().bounds.width - 150) / 2, y: (UIScreen.mainScreen().bounds.height - 100) / 2, width: 150, height: 100)
self.waitView.hidden = false
dispatch_async(dispatch_get_main_queue()) {
self.loadListResultView(indexPath.row)
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
text_search.resignFirstResponder()
self.view.endEditing(true)
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You should create a custom UITableViewCell.
Adding the constraints to UITableViewCell contentView resolved it for me.

IBDesignable - Arrange subviews added through interface builder

I am currently messing around with IBDesignable Views, and I am curious if anyone has been able to solve this. I would like to have views added through the interface builder be automatically arranged using a custom layout algorithm within my subview. The view works great when I run the app, but in the interface builder, the views do not rearrange in real time.
I have tried debugging my UIView class, but it seems at all times when the interface builder is initializing the element, it thinks it has zero subviews. It seems the interface builder does not give you a chance to arrange these views after the fact. However, I'm wondering if maybe there is just something I'm missing. Is it possible to rearrange subviews added from the interface builder within an IBDesignable class, and have the views show up rearranged in the interface builder?
Try using the provided method for a custom view and IBDesignable if you are not already. You also might need to refresh your views in Xcode or have it automatically refresh views. Below is the function you may be missing. This is never called in a live app. It is only called in Xcode IB.
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setUpView()
}
In this instance setUpView is laying out my subviews.
Here is an example that I made. https://github.com/agibson73/ICONButton
import UIKit
#IBDesignable class AGIconButton: UIControl {
private var iconImageView : UIImageView!
private var iconLabel : UILabel!
private var mainSpacer : UIView!
private var highlightView:UIView!
private var widthContraint : NSLayoutConstraint!
var padding : CGFloat = 5
override init(frame: CGRect) {
super.init(frame: frame)
setUpView()
addTarget(self, action: #selector(AGIconButton.userDidTouchDown), for: .touchDown)
addTarget(self, action: #selector(AGIconButton.userDidTouchUp), for: .touchUpInside)
addTarget(self, action: #selector(AGIconButton.userDidTouchUpOutside), for: .touchUpOutside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpView()
addTarget(self, action: #selector(AGIconButton.userDidTouchDown), for: .touchDown)
addTarget(self, action: #selector(AGIconButton.userDidTouchUp), for: .touchUpInside)
addTarget(self, action: #selector(AGIconButton.userDidTouchUpOutside), for: .touchUpOutside)
}
//only called at design time
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setUpView()
addTarget(self, action: #selector(AGIconButton.userDidTouchDown), for: .touchDown)
addTarget(self, action: #selector(AGIconButton.userDidTouchUp), for: .touchUpInside)
addTarget(self, action: #selector(AGIconButton.userDidTouchUpOutside), for: .touchUpOutside)
}
#IBInspectable var iconImage: UIImage = UIImage() {
didSet {
iconImageView.image = iconImage
}
}
#IBInspectable var imageSize: CGFloat = 40 {
didSet {
setUpView()
}
}
#IBInspectable var imagePadding: CGFloat = 10 {
didSet {
setUpView()
}
}
#IBInspectable var iconText: String = "Icon Button Time" {
didSet {
setUpView()
}
}
#IBInspectable var iconTextSize: CGFloat = 15 {
didSet {
setUpView()
}
}
#IBInspectable var iconTextColor: UIColor = UIColor.black {
didSet {
setUpView()
}
}
#IBInspectable var alignment: Int = 1 {
didSet {
setUpView()
}
}
override var intrinsicContentSize: CGSize {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: iconTextSize)
label.text = iconText
label.sizeToFit()
return CGSize(width: imageSize + label.frame.width + imagePadding + (padding * 2), height: CGFloat(max(label.frame.height, imageSize) + padding * 2))
}
#IBInspectable var highLightColor: UIColor = UIColor.lightGray {
didSet {
setUpView()
}
}
#IBInspectable var shouldBounce: Bool = true
#IBInspectable var borderColor: UIColor = UIColor.clear {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
private func setUpView(){
if iconImageView == nil{
iconImageView = UIImageView(image: iconImage)
iconImageView.contentMode = .scaleAspectFit
iconImageView.isUserInteractionEnabled = false
self.addSubview(iconImageView)
}
if mainSpacer == nil{
mainSpacer = UIView(frame: CGRect(x: 0, y: 0, width: imagePadding, height: self.bounds.height))
mainSpacer.isUserInteractionEnabled = false
self.addSubview(mainSpacer)
}
if iconLabel == nil{
iconLabel = UILabel()
iconLabel.isUserInteractionEnabled = false
self.addSubview(iconLabel)
}
if highlightView == nil{
highlightView = UIView(frame: self.bounds)
highlightView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
highlightView.alpha = 0
highlightView.isUserInteractionEnabled = false
self.addSubview(highlightView)
self.bringSubview(toFront: highlightView)
}
highlightView.backgroundColor = highLightColor
iconLabel.font = UIFont.systemFont(ofSize: iconTextSize)
iconLabel.text = iconText
iconLabel.textColor = iconTextColor
iconLabel.sizeToFit()
var usedWidth : CGFloat = self.intrinsicContentSize.width
if bounds.width < usedWidth{
usedWidth = bounds.width
}
let maxImageHeight = min(self.bounds.height - padding, imageSize)
//resize iconlabel if we have to
if maxImageHeight + imagePadding + iconLabel.bounds.width + padding * 2 > usedWidth{
iconLabel.frame = CGRect(x: 0, y: 0, width: self.bounds.width - iconImageView.bounds.width - imagePadding - padding * 2, height: iconLabel.bounds.height)
iconLabel.fitFontForSize(minFontSize: 1, maxFontSize: iconTextSize, accuracy: 1.0)
}
let maxWidth = (self.bounds.width - iconLabel.bounds.width - maxImageHeight - imagePadding) / 2
switch alignment {
case 0:
//intrinsic left
iconImageView.frame = CGRect(x:padding, y: self.bounds.midY - maxImageHeight/2,width:maxImageHeight, height: maxImageHeight)
mainSpacer.frame = CGRect(x: maxImageHeight + padding, y: 0, width: imagePadding, height: self.bounds.height)
iconLabel.frame = CGRect(x: maxImageHeight + imagePadding + padding, y: 0, width: iconLabel.frame.width, height: bounds.height)
break
case 1:
//intrinsic center
iconImageView.frame = CGRect(x: maxWidth, y: self.bounds.midY - maxImageHeight/2,width:maxImageHeight, height: maxImageHeight)
mainSpacer.frame = CGRect(x: maxWidth + maxImageHeight, y: 0, width: imagePadding, height: self.bounds.height)
iconLabel.frame = CGRect(x: maxWidth + maxImageHeight + imagePadding, y: 0, width: iconLabel.frame.width, height: self.bounds.height)
break
case 2:
//intrinsic icon right text aligned right
iconLabel.frame = CGRect(x: maxWidth, y: 0, width: iconLabel.frame.width, height: self.bounds.height)
iconLabel.textAlignment = .right
mainSpacer.frame = CGRect(x: iconLabel.frame.width + maxWidth, y: 0, width: imagePadding, height: self.bounds.height)
iconImageView.frame = CGRect(x: iconLabel.frame.width + imagePadding + maxWidth, y: self.bounds.midY - maxImageHeight/2,width:maxImageHeight, height: maxImageHeight)
break
case 3:
//intrinsic center invert icon
iconLabel.frame = CGRect(x:maxWidth, y: 0, width: iconLabel.frame.width, height: self.bounds.height)
mainSpacer.frame = CGRect(x: maxWidth + iconLabel.bounds.width, y: 0, width: imagePadding, height: self.bounds.height)
iconImageView.frame = CGRect(x: maxWidth + iconLabel.bounds.width + imagePadding, y: self.bounds.midY - maxImageHeight/2,width:maxImageHeight, height: maxImageHeight)
break
default:
//intrinsic center
iconImageView.frame = CGRect(x: maxWidth, y: self.bounds.midY - maxImageHeight/2,width:maxImageHeight, height: maxImageHeight)
mainSpacer.frame = CGRect(x: maxWidth + maxImageHeight, y: 0, width: imagePadding, height: self.bounds.height)
iconLabel.frame = CGRect(x: maxWidth + maxImageHeight + imagePadding, y: 0, width: iconLabel.frame.width, height: self.bounds.height)
}
}
//layout subviews
override func layoutSubviews() {
super.layoutSubviews()
setUpView()
}
//MARK: Touch Events
//TODO: run on timer to simulate a real press
func userDidTouchDown(){
if shouldBounce == true{
animateBouncyDown()
}else{
self.animateHighlightTo(alpha: 0.3)
}
}
func userDidTouchUp(){
if shouldBounce == true{
animateBouncyUp()
}else{
self.animateHighlightTo(alpha: 0)
}
}
func userDidTouchUpOutside(){
if shouldBounce == true{
animateBouncyUp()
}else{
self.animateHighlightTo(alpha: 0)
}
}
func animateHighlightTo(alpha:CGFloat){
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.highlightView.alpha = alpha
})
}
func animateBouncyDown(){
self.transform = CGAffineTransform.identity
UIView.animate(withDuration: 0.15, animations: { [weak self] in
self?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
})
}
func animateBouncyUp(){
UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: .curveEaseInOut, animations: {[weak self] in
if self != nil{
self?.transform = CGAffineTransform.identity
}
}, completion: nil)
}
}
extension UILabel {
func fitFontForSize( minFontSize : CGFloat = 1.0, maxFontSize : CGFloat = 300.0, accuracy : CGFloat = 1.0) {
var maxFontSize = maxFontSize
var minFontSize = minFontSize
assert(maxFontSize > minFontSize)
layoutIfNeeded() // Can be removed at your own discretion
let constrainedSize = bounds.size
while maxFontSize - minFontSize > accuracy {
let midFontSize : CGFloat = ((minFontSize + maxFontSize) / 2)
font = font.withSize(midFontSize)
sizeToFit()
let checkSize : CGSize = bounds.size
if checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
minFontSize = midFontSize
} else {
maxFontSize = midFontSize
}
}
font = font.withSize(minFontSize)
sizeToFit()
layoutIfNeeded()
}
}
There doesn't seem to be any way to do this. If you drop a custom control into another xib and add subviews to the custom control in Interface Builder, those subviews appear at the same level as the custom control in the view hierarchy when you load the xib. It looks like custom controls can not act as containers in other xibs.

Resources