Multiple buttons on iPhone - Swift - swift

I am trying to put multiple buttons on an iPhone app with an function, only when I run the function the 2nd time , does the button show. It doesn't show the two buttons which I have configured it to run.
class ViewController: UIViewController {
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
let screensize: CGRect = UIScreen.mainScreen().bounds
override func viewDidLoad() {
super.viewDidLoad()
println(screensize.size.height)
blur()
// add iphone 2 buttons
let rect : CGRect = CGRectMake(100, 50, 200, 50)
var rectObj = NSValue(CGRect: rect)
showButton("Hello", rect: rectObj, redvalue: 1.0, greenvalue: 0.5, bluevalue: 0.5, alphavalue: 1.0)
let rect1 : CGRect = CGRectMake(20, 50, 200, 50)
var rectObj1 = NSValue(CGRect: rect)
showButton("Good bye", rect: rectObj1, redvalue: 0.5, greenvalue: 0.5, bluevalue: 0.5, alphavalue: 1.0)
}
func showButton(title: String, rect: NSValue, redvalue : CGFloat, greenvalue: CGFloat, bluevalue: CGFloat, alphavalue : CGFloat)
{
var rectRestored : CGRect = rect.CGRectValue()
button.frame = CGRectMake(rectRestored.origin.x, rectRestored.origin.y, rectRestored.width, rectRestored.height)
button.backgroundColor = UIColor(red: redvalue , green: greenvalue, blue: bluevalue, alpha: alphavalue)
button.setTitle(title, forState: UIControlState.Normal)
self.view.addSubview(button)
}
func blur()
{
var blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
blur.frame = self.view.frame
self.view.addSubview(blur)
}
Does addSubView overwrite it ? If so I have tried insersubview : index and that doesn't seem to work either.

Try to call the method in viewWillAppear insted of viewDidLoad, because in viewDidLoad you still may not have the appropriate frame for main view.

Related

SnapKit and custom gradient button Swift

I use SnapKit in my project and trying to add gradient on my button
I have extension:
extension UIButton {
public func setGradientColor(colorOne: UIColor, colorTwo: UIColor) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
layer.insertSublayer(gradientLayer, at: 0)
}
}
i have button config where i am trying to use gradient:
private var playersButton: UIButton = {
let button = UIButton(type: .custom)
button.setGradientColor(colorOne: .red, colorTwo: .blue)
button.frame = button.layer.frame
return button
}()
and SnapKit here
playersButton.snp.makeConstraints { make in
make.leading.equalToSuperview().inset(60)
make.trailing.equalToSuperview().inset(60)
make.bottom.equalTo(startGameButton).inset(100)
make.height.equalTo(screenHeight/12.82)
}
The problem is i have not result of it, i dont see gradientm but if i delete snapKit config and will use setGradient extension in viewDidLoad it works well!
Example:
private var playersButton: UIButton = {
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
playersButton.setGradientColor(colorOne: .blue, colorTwo: .red)
}
How do i change my code to use first method? Thank you
The difference is that when using SnapKit you're using Auto-Layout, so your button's frame is not set when you call button.setGradientColor(colorOne: .red, colorTwo: .blue).
The result is that your gradient layer ends up with a frame size of Zero - so you don't see it.
You will likely find it much easier and more reliable to use a button subclass like this (simple example based on the code you posted):
class MyGradientButton: UIButton {
let gradLayer = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
layer.insertSublayer(gradLayer, at: 0)
}
public func setGradientColor(colorOne: UIColor, colorTwo: UIColor) {
gradLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradLayer.locations = [0.0, 1.0]
gradLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
}
override func layoutSubviews() {
super.layoutSubviews()
gradLayer.frame = bounds
}
}
Then change your button declaration to:
private var playersButton: MyGradientButton = {
let button = MyGradientButton()
button.setGradientColor(colorOne: .red, colorTwo: .blue)
return button
}()
Now, whether you set its frame explicitly, or if you use auto-layout (normal syntax or with SnapKit), the gradient layer will automatically adjust whenever the button's frame changes.

how do i fix this error when i try and set the color of a border to a gradient color

I have created a messaging app and I want to set the border colour as a gradient instead of just a solid colour.
So far when I run my code this is what is see:
The gradient colour is supposed to be a border colour for each message cell
I don't know what is making it look the way it does
this is how I coded it :
I've created an extension to deal with the gradient and it looks like this:
extension UIView {
func gradientButton( startColor:UIColor, endColor:UIColor) {
let view:UIView = UIView(frame: self.bounds)
let gradient = CAGradientLayer()
gradient.colors = [startColor.cgColor, endColor.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
gradient.frame = self.bounds
self.layer.insertSublayer(gradient, at: 0)
self.mask = view
view.layer.borderWidth = 2
}
}
and when I set the gradient I set it like this in my chatController class
class ChatController: UICollectionViewController, UICollectionViewDelegateFlowLayout, ChatCellSettingsDelegate {
func configureMessage(cell: ChatCell, message: Message) {
cell.bubbleView.gradientButton(startColor: blue, endColor: green)
}
The bubbleView holds the text which is a textView of the message which is created in my ChatCell class:
class ChatCell: UICollectionViewCell {
let bubbleView: UIView = {
let bubble = UIView()
bubble.backgroundColor = UIColor.rgb(red: 0, green: 171, blue: 154, alpha: 1)
bubble.translatesAutoresizingMaskIntoConstraints = false
bubble.layer.masksToBounds = true
bubble.layer.cornerRadius = 13
bubble.backgroundColor = .white
return bubble
}()
let textView: UITextView = {
let text = UITextView()
text.text = "test"
text.font = UIFont.systemFont(ofSize: 16)
text.backgroundColor = .clear
text.translatesAutoresizingMaskIntoConstraints = false
text.isEditable = false
return text
}()
}
how do I fix this?
any help would be helpful
thank you
I can set the border colour to a solid colour with the following line:
cell.bubbleView.layer.borderColor = UIColor.rgb(red: 91, green: 184, blue: 153, alpha: 0.8).cgColor
and then it would look like this:
You can create your own bordered view and use it in your custom cell:
import UIKit
import PlaygroundSupport
public class GradientBorder: UIView {
var startColor: UIColor = .black
var endColor: UIColor = .white
var startLocation: Double = 0.05
var endLocation: Double = 0.95
var path: UIBezierPath!
let shape = CAShapeLayer()
var lineWidth: CGFloat = 5
override public class var layerClass: AnyClass { CAGradientLayer.self }
var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }
func update() {
gradientLayer.startPoint = .init(x: 0.0, y: 0.5)
gradientLayer.endPoint = .init(x: 1.0, y: 0.5)
gradientLayer.locations = [startLocation as NSNumber, endLocation as NSNumber]
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
path = .init(roundedRect: bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2), byRoundingCorners: [.topLeft, .bottomLeft, .topRight, .bottomRight], cornerRadii: CGSize(width: frame.size.height / 2, height: frame.size.height / 2))
shape.lineWidth = lineWidth
shape.path = path.cgPath
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
gradientLayer.mask = shape
}
override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
update()
}
}
Playground testing:
let gradientBorderedView = GradientBorder()
gradientBorderedView.frame = .init(origin: .zero, size: .init(width: 200, height: 40))
let view = UIView()
view.frame = .init(origin: .zero, size: .init(width: 375, height: 812))
view.backgroundColor = .blue
view.addSubview(gradientBorderedView)
PlaygroundPage.current.liveView = view

How to only show bottom border for segmented control in xcode

I have the following code
extension UITextField {
func setPadding() {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: self.frame.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setBottomBorder() {
self.layer.shadowColor = UIColor.white.cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
self.layer.shadowOpacity = 1.0
self.layer.shadowRadius = 0.0
}
}
extension UISegmentedControl {
func removeBorder(){
let backgroundImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: self.bounds.size)
self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default)
self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default)
let deviderImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: CGSize(width: 1.0, height: self.bounds.size.height))
self.setDividerImage(deviderImage, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.gray], for: .normal)
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)], for: .selected)
}
func addUnderlineForSelectedSegment(){
removeBorder()
let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments)
let underlineHeight: CGFloat = 2.0
let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth))
let underLineYPosition = self.bounds.size.height - 1.0
let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight)
let underline = UIView(frame: underlineFrame)
underline.backgroundColor = UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)
underline.tag = 1
self.addSubview(underline)
}
func changeUnderlinePosition(){
guard let underline = self.viewWithTag(1) else {return}
let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex)
UIView.animate(withDuration: 0.1, animations: {
underline.frame.origin.x = underlineFinalXPosition
})
}
}
extension UIImage {
class func getColoredRectImageWith(color: CGColor, andSize size: CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let graphicsContext = UIGraphicsGetCurrentContext()
graphicsContext?.setFillColor(color)
let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
graphicsContext?.fill(rectangle)
let rectangleImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return rectangleImage!
}
}
class ViewController: UIViewController {
#IBAction func segmentedControl(_ sender: UISegmentedControl) {
print("djfdd")
sender.changeUnderlinePosition()
}
When I run the project the segmentedControl is normal and no changes have been applied. I have been stuck with this issue and and I can't figure out what I'm doing wrong. I am also not getting any error messages.
EDIT
The way I created the segmented control was adding it in storybard, I did not give it a class. Then to create the action I simply left clicked and dragged it into my viewcontroller.swift. I also have not added any constraints.
You're creating a new instance of UISegmentedControl in the segmentedControlDidChange and applying the changes. This won't apply the changes to the existing SegmentedControl. Here's want you've to do to apply those changes to the existing UISegmentedControl. Modify the segmentedControlDidChange method as follows:
#IBAction func segmentedControlDidChange(_ sender: UISegmentedControl) {
sender.changeUnderlinePosition()
}

Swift - Customizing UISearchBar design programmatically

I'm trying to customize UISearchBar design programmatically. I tried adding a bunch of codes but only a few places are changed.
This is the design I want to create.
And this is how it looks now.
I screen-captured the second image from the simulator so it's bigger.
Anyways, I'm trying to make my search bar has
Lighter background color
Shorter textfield in height
Textfield to have less corner radious
Here are my codes:
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 60))
[In viewDidLoad()]
searchBar.delegate = self
searchBar.isTranslucent = false
searchBar.placeholder = "Search the phrase"
searchBar.tintColor = UIColor(red:0.73, green:0.76, blue:0.78, alpha:1.0)
searchBar.setImage(UIImage(named: "search"), for: .search, state: .normal)
let forTextField = searchBar.value(forKey: "searchField") as? UITextField
forTextField?.textColor = UIColor(red:0.31, green:0.31, blue:0.31, alpha:1.0)
forTextField?.font = UIFont(name: "HelveticaNeue-Light", size: 14)
forTextField?.clipsToBounds = true
forTextField?.layer.cornerRadius = 5
forTextField?.frame.size.height = 30
I would appreciate your help!
Here is the way you can achieve that:
class ViewController: UIViewController, UISearchBarDelegate {
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 60))
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
searchBar.isTranslucent = false
searchBar.placeholder = "Search the phrase"
searchBar.tintColor = UIColor(red:0.73, green:0.76, blue:0.78, alpha:1.0)
//1. Lighter background color
searchBar.barTintColor = UIColor(netHex: 0xE6E6E6)
self.view.addSubview(searchBar)
}
override func viewDidAppear(_ animated: Bool) {
for subView in searchBar.subviews {
for subsubView in subView.subviews {
if let textField = subsubView as? UITextField {
var bounds: CGRect
bounds = textField.frame
//2. Shorter textfield in height
bounds.size.height = 28
textField.bounds = bounds
//3. Textfield to have less corner radious
textField.layer.cornerRadius = 5 //Probably you can play with this and see the changes.
textField.clipsToBounds = true
}
}
}
}
}
extension UIColor {
convenience init(r: Int, g: Int, b: Int, a: Int = 255) {
self.init(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: CGFloat(a) / 255.0)
}
convenience init(netHex:Int) {
self.init(r:(netHex >> 16) & 0xff, g:(netHex >> 8) & 0xff, b:netHex & 0xff)
}
}

my drawRect function will not update

I want the values for the colors of the circle to update when the variables(redd1,greenn1,bluee1) are changed by the steppers in my ViewController. The original circle is drawn by drawRect.
var redd1 = 0.0;
var greenn1 = 0.0;
var bluee1 = 0.0;
override init(frame: CGRect)
{
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect)
{
let circle2 = UIView(frame: CGRect(x: -25.0, y: 10.0, width: 100.0, height:100.0))
circle2.layer.cornerRadius = 50.0
let startingColor2 = UIColor(red: (CGFloat(redd1))/255, green: (CGFloat (greenn1))/255, blue: (CGFloat(bluee1))/255, alpha: 1.0)
circle2.backgroundColor = startingColor2;
addSubview(circle2);
}
I tried creating a new function that draws a new circle on top of the old one. It is called by the stepper. The new function, updateColor(), receives the new value from the stepper. This partially works because it prints out the correct new values, but never draws the new circle.
func updateColor()
{
let circle = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
circle.layer.cornerRadius = 50.0;
let startingColor = UIColor(red: (CGFloat(redd1))/255, green: (CGFloat(greenn1))/255, blue: (CGFloat(bluee1))/255, alpha: 1.0)
circle.backgroundColor = startingColor;
addSubview(circle);
}
I'm not so good in Swift, but that's a simple way how i wood do it:
var circle2: UIView
override func drawRect(rect: CGRect) {
circle2 = UIView(frame: CGRect(x: -25.0, y: 10.0, width: 100.0, height:100.0))
circle2.layer.cornerRadius = 50.0
let startingColor2 = UIColor(red: (CGFloat(redd1))/255, green: (CGFloat (greenn1))/255, blue: (CGFloat(bluee1))/255, alpha: 1.0)
circle2.backgroundColor = startingColor2;
addSubview(circle2);
}
#IBAction valueChanged(sender: UIStepper) {
changeColor(color(the Color you want), Int(the Int value you want the color to change at))
}
func changeColor(color: UIColor, number: Int) {
if stepper.value == number {
circle2.backgroundColor = color
}
}
You have to create a IBAction for the stepper of the type value changed and call the method for every color and to it belonging Int in the IBAction for the stepper. So every time + or - on the stepper is pressed the IBAction calls the changeColor method and the changeColor method tests which color should be set to circle2.