How can I create an animated and shadowed button like in this video
(Once you click the button, it shines and swings)
Here is my code:
(This code implement swing and shadow but needs to be organized and arranged so that it is capable of running the light and the swing with one click and the button doesn't move from its place unnecessarily)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var aBtn: ButtonWithShadow!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func btnClick(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.50).cgColor
sender.layer.shadowOffset = CGSize(width: 0, height: 3)
sender.layer.shadowOpacity = 1.0
sender.layer.shadowRadius = 10.0
sender.layer.masksToBounds = false
} else {
sender.isSelected = true
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.0).cgColor
}
aBtn.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
aBtn.layer.transform = CATransform3DMakeRotation(-.pi / 15, 0, 0, 1)
let needleAnim = CABasicAnimation(keyPath: "transform.rotation.z")
needleAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
needleAnim.duration = 1.0 as? CFTimeInterval ?? CFTimeInterval()
needleAnim.repeatCount = 5
needleAnim.autoreverses = true
// Setting fillMode means that, once the animation finishes, the needle stays in its end position.
needleAnim.fillMode = kCAFillModeForwards
needleAnim.isRemovedOnCompletion = true
needleAnim.toValue = Double.pi / 15
aBtn.layer.add(needleAnim, forKey: nil)
}
}
and
import UIKit
class ButtonWithShadow: UIButton {
override func draw(_ rect: CGRect) {
//updateLayerProperties()
}
}
Thanks for your time
Your code works as written and provides a swinging button when clicked. Make sure you control-click dragged from the button to the button definition.
You'll need to add two images to your button, one for the off state and one for the on state.
and on
Here is the intermediate result of adding setting the images.
and the way to change the images is to add them to the assets catalog and then change them with :
if sender.isSelected {
sender.isSelected = false
sender.setImage(#imageLiteral(resourceName: "off"), for: .normal)
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.50).cgColor
sender.layer.shadowOffset = CGSize(width: 0, height: 3)
sender.layer.shadowOpacity = 1.0
sender.layer.shadowRadius = 10.0
sender.layer.masksToBounds = false
} else {
sender.isSelected = true
sender.setImage(#imageLiteral(resourceName: "onbtn"), for: .normal)
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.0).cgColor
}
Related
I tried to create custom segmented control which should change its look if you are hovering it. But it does not work as I expected.
Here's the code (I am sorry that it is that long but I already made it 200 lines shorter then it was):
class MySegmentedControl: UIView {
var state = MySegmentedControl_State.unknown
var buttons = [MySegmentedControl_ButtonView]()
func setUpView(){
let view = UIView(frame: self.frame)
view.frame.origin.x = 0
view.frame.origin.y = 0
view.addSubview(holderView())
self.addSubview(view)
}
func holderView() -> UIView{
let view = UIView(frame: CGRect(origin: CGPoint(x: 100, y: 0), size: CGSize(width: 490, height: 70)))
view.layer.borderWidth = 5
view.layer.borderColor = UIColor.gray.cgColor
view.layer.cornerRadius = view.frame.height / 2
view.layer.masksToBounds = true
view.clipsToBounds = true
view.backgroundColor = #colorLiteral(red: 0.5741485357, green: 0.5741624236, blue: 0.574154973, alpha: 1)
//place the first button
let button_1 = MySegmentedControl_ButtonView(text: "One", frame: CGRect(x: 0, y: 0, width: 163.3333, height: 70), type: .one, delegate: self)
//place the second Button
let button_2 = MySegmentedControl_ButtonView(text: "Two", frame: CGRect(x: 163.3333, y: 0, width: 163.3333, height: 70), type: .two, delegate: self)
//place the third Button
let button_3 = MySegmentedControl_ButtonView(text: "Three", frame: CGRect(x: 163.3333*2, y: 0, width: 163.3333, height: 70), type: .three, delegate: self)
buttons.append(button_1); buttons.append(button_2); buttons.append(button_3)
view.addSubview(button_1)
view.addSubview(button_2)
view.addSubview(button_3)
return view
}
class MySegmentedControl_ButtonView: UIView{
private var selected = false
private var hovering = false
var text = ""
private var type: MySegmentedControl_State
private var delegate: MySegmentedControl_ButtonView_Delegate
private var label = UILabel()
func setUpView(){
layer.cornerRadius = frame.height/2
let label = UILabel(frame: frame)
self.label = label
label.tintColor = .white
label.text = text
label.sizeToFit()
label.center = self.center
label.font = label.font.withSize(15)
let regionizer = UIHoverGestureRecognizer(target: self, action: #selector(didHover(_:)))
addGestureRecognizer(regionizer)
addSubview(label)
//set up the button
let button = UIButton(frame: bounds, primaryAction: UIAction(handler: { [self] action in
selected = true
delegate.shouldChangeState(to: type)
delegate.shouldDeselectOthers(without: text)
if !hovering{
backgroundColor = #colorLiteral(red: 0.9961533629, green: 0.9931518435, blue: 1, alpha: 0.8)
}else{
self.backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.9435433103)
}
}))
addSubview(button)
}
func deselect(){
self.selected = false
if hovering{
backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}else{
backgroundColor = #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260515637, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}
}
#objc
func didHover(_ recognizer: UIHoverGestureRecognizer){
switch recognizer.state{
case .began, .changed:
hovering = true
if selected{
backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}else{
backgroundColor = #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260515637, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}
case .ended:
hovering = false
if selected{
self.backgroundColor = #colorLiteral(red: 0.9961533629, green: 0.9931518435, blue: 1, alpha: 0.2)
UIView.animate(withDuration: 0.2) {[self]in
label.center.y = center.y
label.font = label.font.withSize(15)
}
}else{
self.backgroundColor = .clear
UIView.animate(withDuration: 0.2) {[self]in
label.center.y = center.y
label.font = label.font.withSize(15)
}
}
default:break
}
}
init(text: String, frame: CGRect, type: MySegmentedControl_State, delegate: MySegmentedControl_ButtonView_Delegate){
self.type = type
self.delegate = delegate
super.init(frame: frame)
self.text = text
setUpView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
extension MySegmentedControl: MySegmentedControl_ButtonView_Delegate{
func shouldDeselectOthers(without: String) {
for button in buttons{
if button.text != without{
button.deselect()
}
}
}
func shouldChangeState(to state: MySegmentedControl_State) {
self.state = state
}
}
protocol MySegmentedControl_ButtonView_Delegate{
func shouldDeselectOthers(without: String)
func shouldChangeState(to state: MySegmentedControl_State)
}
enum MySegmentedControl_State: String{
case unknown = "Non specific case avalaible"
case one = "One selected"
case two = "Two selected"
case three = "Three selected"
}
But the second of my buttons is displayed as the third and the the third does not get displayed, but if I hover the place where button two SHOULD be, it still gets hovered.
Here is a shout video:
Video showing problems with this code
My App is running on MacOS with MacCatalyst
In setUpView() inside class MySegmentedControl_ButtonView, you are trying to set the label's position with:
label.center = self.center
However, self.center is relative to self's superview. So your labels are being shifted.
If you change that line to:
label.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
the label centering will be correct.
As I asked in my comment though... why aren't you using auto-layout? It would make things much easier (and much more flexible).
I am trying to programmatically create 6 CGRect objects on the right side of the screen, with three being blue and three red. The user would then drag them to the left side of the screen, and they need to drag the blue blocks where the target is the faded-out region of the same color. The picture below depicts what I am trying to do.
The issue is that when I drag any block over any of the faded areas, it accepts the block and deletes it. I realize that I need to implement shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer but I am confused on how to do so. I get that gestureRecognizer and otherGestureRecognizer represent the two conflicting objects, but I don't know how to implement it with the rest of my code so that I can make sure that only blue blocks can go over the faded blue block and activate the delete feature. What I have is below.
import UIKit
class ViewController: UIViewController {
private struct Constants {
static let padding: CGFloat = 75
static let correctPadding: CGFloat = 0
static let blockDimension: CGFloat = 50
}
var targetView0: UIView?
var targetView1: UIView?
var targetView2: UIView?
var targetView3: UIView?
var targetView4: UIView?
var targetView5: UIView?
var beginningPosition: CGPoint = .zero
var initialMovableViewPosition: CGPoint = .zero
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
addMovableViews(count: 6)
addtargetView0()
addtargetView1()
addtargetView2()
addtargetView3()
addtargetView4()
addtargetView5()
}
//This programtically creates the blocks w/ x and y
private func addMovableViews(count: Int) {
var xOffset = Constants.padding
for i in 0..<count {
print(i)
let movableView = UIView(frame: CGRect(x: 700, y: xOffset + 120, width: Constants.blockDimension, height: Constants.blockDimension))
if (i == 0) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item0)
} else if (i == 1) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item1 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item1)
} else if (i == 2) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item2 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item2)
} else if (i == 3) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item3 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item3)
} else if (i == 4) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item4 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item4)
} else if (i == 5) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item5 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item5)
} else if (i == 6) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item6 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item6)
}
xOffset += Constants.blockDimension + Constants.padding
}
}
private func addtargetView0() {
let xOffset = Constants.correctPadding
targetView0 = UIView(frame: CGRect(x: xOffset + 100, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView0?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView0!)
}
private func addtargetView1() {
let xOffset = Constants.correctPadding
targetView1 = UIView(frame: CGRect(x: 100 + xOffset + 50, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView1?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView1!)
}
private func addtargetView2() {
let xOffset = Constants.correctPadding
targetView2 = UIView(frame: CGRect(x: 100 + xOffset + 100, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView2?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView2!)
}
private func addtargetView3() {
let xOffset = Constants.correctPadding
targetView3 = UIView(frame: CGRect(x: 100 + xOffset + 150, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView3?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView3!)
}
private func addtargetView4() {
let xOffset = Constants.correctPadding
targetView4 = UIView(frame: CGRect(x: 100 + xOffset + 200, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView4?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView4!)
}
private func addtargetView5() {
let xOffset = Constants.correctPadding
targetView5 = UIView(frame: CGRect(x: 100 + xOffset + 250, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView5?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView5!)
}
//Gesture recognizer
#objc private func touched(_ gestureRecognizer: UIGestureRecognizer) {
if let touchedView = gestureRecognizer.view {
if gestureRecognizer.state == .began {
beginningPosition = gestureRecognizer.location(in: touchedView)
initialMovableViewPosition = touchedView.frame.origin
} else if gestureRecognizer.state == .ended {
//Moves it back to where it was
// touchedView.frame.origin = initialMovableViewPosition
} else if gestureRecognizer.state == .changed {
let locationInView = gestureRecognizer.location(in: touchedView)
touchedView.frame.origin = CGPoint(x: touchedView.frame.origin.x + locationInView.x - beginningPosition.x, y: touchedView.frame.origin.y + locationInView.y - beginningPosition.y)
if touchedView.frame.intersects(targetView0!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView1!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView1?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView2!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView2?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView3!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView3?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView4!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView4?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView5!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView5?.backgroundColor = .red
initialMovableViewPosition = .zero
}
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
-> Bool {
// If the gesture recognizers are on diferent views, do not allow
// simultaneous recognition.
if gestureRecognizer.view != otherGestureRecognizer.view {
return false
}
return true
}
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Can someone explain how to incorporate shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer, link a complete project doing something similar, or walk me through it. Any help is appreciated.
There are a few issues here. Firstly, the delegate for your gestures are not being set. To do this, you need ViewController to extend UIGestureRecognizerDelegate like so class ViewController: UIViewController, UIGestureRecognizerDelegate. Then, you need to set the delegate of each of your gestures to your ViewController:
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
item0.delegate = self
movableView.addGestureRecognizer(item0)
Second, even with the delegates set, shouldRecognizeSimultaneouslyWith would never be called since you only have one type of gesture (UIPanGestureRecognizer) for each of your moveable views. Your target views themselves do not have any gesture recognisers assigned to them. If you want to test when shouldRecognizeSimultaneouslyWith is called, you can try do the following:
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
item0.delegate = self
movableView.addGestureRecognizer(item0)
// Add another gesture
let testitem = UITapGestureRecognizer(target: self, action: #selector(test))
movableView.addGestureRecognizer(testitem)
With the example above, both UITapGestureRecognizer and UIPanGestureRecognizer would be triggered the moment you start dragging the moveable views.
=== Solution ===
Instead of using shouldRecognizeSimultaneouslyWith might I suggest adding tags to each of your moveable and target views? For example, for all blue moveable and target views, movableView.tag = 0 and for all red moveable and target views, movableView.tag = 1.
Then, in your touched action, you can just check if the tags match like so:
if touchedView.frame.intersects(targetView0!.frame) {
if touchedView.tag == targetView0?.tag {
touchedView.removeFromSuperview()
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
}
I figured it out. It's basically just in the gesture if statement.
#objc private func touched(_ gestureRecognizer: UIGestureRecognizer) {
if let touchedView = gestureRecognizer.view {
if gestureRecognizer.state == .began {
beginningPosition = gestureRecognizer.location(in: touchedView)
initialMovableViewPosition = touchedView.frame.origin
} else if gestureRecognizer.state == .ended {
//Moves it back to where it was
// touchedView.frame.origin = initialMovableViewPosition
} else if gestureRecognizer.state == .changed {
let locationInView = gestureRecognizer.location(in: touchedView)
touchedView.frame.origin = CGPoint(x: touchedView.frame.origin.x + locationInView.x - beginningPosition.x, y: touchedView.frame.origin.y + locationInView.y - beginningPosition.y)
if ((touchedView.backgroundColor == .blue) && (targetView0?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView0!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView1?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView1!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView1?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .blue) && (targetView2?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView2!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView2?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView3?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView3!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView3?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .blue) && (targetView4?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView4!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView4?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView5?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView5!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView5?.backgroundColor = .red
initialMovableViewPosition = .zero
}
}
}
}
You check if the gestureRecognizer background color is blue, check if the targetView background color is the faded blue via UIColor, and see if the view intersects, and then you do what you need. You can even do it to fill the target view in the order you want with an additional if statement.
I'm trying to implement AZTabBarController within my project but I am struggling to fix the bar to the bottom of the screen. My assumption is that the bar can be fixed to the bottom using some method or that I have some element that is pushing the bar some 50pts higher. Perhaps there is a margin of some sort that keeps the bar from staying at the bottom. Any suggestions will be much appreciated.
Here is my AZTabBar code. I've borrowed it from the example within the repo.
class CustomTabBarController: UITabBarController {
var tabController: AZTabBarController!
override func viewDidLoad() {
super.viewDidLoad()
var icons = [UIImage]()
icons.append(UIImage.init(named: "ic_home")!)
icons.append(UIImage.init(named: "ic_new")!)
icons.append(UIImage.init(named: "ic_settings")!)
//The icons that will be displayed for each tab once they are selected.
var selectedIcons = [UIImage]()
selectedIcons.append(UIImage.init(named: "ic_home")!)
selectedIcons.append(UIImage.init(named: "ic_new")!)
selectedIcons.append(UIImage.init(named: "ic_settings")!)
tabController = AZTabBarController.insert(into: self, withTabIcons: icons, andSelectedIcons: selectedIcons)
tabController.delegate = self
tabController.setViewController(QueryViewController.instance(), atIndex: 0)
tabController.setViewController(SettingsViewController.instance(), atIndex: 2)
//customize
let color = UIColor(red: 14.0/255, green: 122.0/255, blue: 254.0/255, alpha: 1.0)
tabController.selectedColor = color
tabController.highlightColor = color
tabController.highlightedBackgroundColor = #colorLiteral(red: 0.1803921569, green: 0.8, blue: 0.4431372549, alpha: 1)
tabController.defaultColor = .lightGray
//tabController.highlightButton(atIndex: 2)
tabController.buttonsBackgroundColor = UIColor(red: (247.0/255), green: (247.0/255), blue: (247.0/255), alpha: 1.0)//#colorLiteral(red: 0.2039215686, green: 0.2862745098, blue: 0.368627451, alpha: 1)
tabController.selectionIndicatorHeight = 0
tabController.selectionIndicatorColor = color
tabController.tabBarHeight = 60
tabController.setAction(atIndex: 0) {
//Your statments
print("Home!")
}
tabController.setAction(atIndex: 1) {
//Your statments
print("NEW Situation!")
}
tabController.setAction(atIndex: 2) {
//Your statments
print("Settings")
}
tabController.animateTabChange = false
tabController.onlyShowTextForSelectedButtons = false
tabController.setTitle("Home", atIndex: 0)
tabController.setTitle("New", atIndex: 1)
tabController.setTitle("Settings", atIndex: 2)
//tabController.font = UIFont(name: "AvenirNext-Regular", size: 12)
}
override var childForStatusBarStyle: UIViewController?{
return tabController
}
func getNavigationController(root: UIViewController)->UINavigationController{
let navigationController = UINavigationController(rootViewController: root)
navigationController.title = title
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.barStyle = .black
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.barTintColor = #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)
return navigationController
}
}
Sub classing
class CustomTabBarController: UITabBarController {
is the reason you should use AZTabBarController directly , what you see as margin in bottom is the parent class's tabBar which is empty because you don't set any viewControllers for it
Switch statement works but won't reset view background colours etc.
I have a UIImage (icon) and a UIButton embedded within a UIView (of custom type DropShadowCircleView) as per image below.
When the walking button is tapped a var navigationOption is set to either walking or driving and setupNavigationSelectionView() is executed.
Problem is: case "walking" of the switch works perfectly, but case "driving" doesn't reset the UIView and icon tint color witcback to their original setting eg; background color etc.. any ideas why?
func setupNavigationSelectionView(){
switch navigationOption {
case "walking":
walkingBg.setGradientBackground(colourOne: softGreen, ColourTwo: softBlue)
walkingBg.layer.cornerRadius = walkingBg.frame.width / 2
walkingBg.clipsToBounds = true
walkingIcon.tintColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
case "driving":
walkingBg.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
walkingBg.layer.cornerRadius = walkingBg.frame.width / 2
walkingBg.clipsToBounds = true
walkingIcon.tintColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
default:
break
}
}
EDIT: this is my DropShadowCircleView class
class DropShadowCircleView: UIView {
override func awakeFromNib() {
setupView()
super.awakeFromNib()
}
func setupView(){
self.layer.shadowOpacity = 0.50
self.layer.shadowRadius = 20
self.layer.shadowColor = UIColor.black.cgColor
self.layer.cornerRadius = self.frame.width / 2
}
}
EDIT: This is my setGradientBackground function which is within an extension file to UIView
func setGradientBackground(colourOne: UIColor, ColourTwo: UIColor) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = [colourOne.cgColor, ColourTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 1.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
layer.insertSublayer(gradientLayer, at: 0)
}
You need to remove your gradient layer when you reset your icon.
Add this to your extension UIView:
func removeGradientBackground() {
guard
let idx = layer.sublayers?.index(where: { $0 is CAGradientLayer })
else { return }
layer.sublayers?.remove(at: idx)
}
and call it when you are resetting your icon.
I was developing in Swift 3 and I had a little problem with a UIButton. I will try to explain my problem. First I created my UIButton:
let Button: UIButton = {
let button = UIButton(type: .system)
button.setBackgroundImage(UIImage(named: "button"), for: .normal)
button.layer.borderWidth = 2
button.layer.borderColor = UIColor(red: 0, green: 0, blue: 80/255, alpha: 1).cgColor
button.layer.cornerRadius = 10
//button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
After in the viewDidLoad I implemented the action:
button.addTarget(self, action: #selector(buttonUnpressed), for: .touchUpInside)
In which "favButtonPressed" is a function with no importance
The problem is when I touch the button the border doesn't get unhighlighted as the image or the text does. It is a detail of little importance but quite annoying.
I have tried changing the alpha value when pressed and re-change it but the problem is i dont know how to animate it to make the animation for 2 seconds (the next line of code doesnt work, it does change the color but not during 2 seconds):
func buttonUnpressed(){
UIButton.animate(withDuration: 2, animations: {
self.button.layer.borderColor = UIColor(red: 0, green: 0, blue: 80/255, alpha: 1).cgColor
})
}
The question; is there any way of adding the border to the UIButton "total behavior" of highlighting and unhighlighting when pressed?
Excuse me for my english if there are some expression or gramatical faults.
EDIT
I tried with this function:
func buttonUnpressed(){
button.alpha = 0.2
UIButton.animate(withDuration: 1) {
self.button.alpha = 1
}
button.layer.borderColor = UIColor(red: 0, green: 0, blue: 80/255, alpha: 1).cgColor
}
there is a weird highlight of the image but now it works more or less.
You can use this extension to animate change of border color:
extension UIButton {
func borderColorAnimation(from: CGColor, to: CGColor, duration: CFTimeInterval) {
let animation = CABasicAnimation(keyPath: "borderColor")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.fromValue = from
animation.toValue = to
animation.duration = duration
self.layer.add(animation, forKey: "borderColor")
self.layer.borderColor = to
}
}
Like this:
let fromColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1).cgColor
let toColor = UIColor(red: 255, green: 0, blue: 0, alpha: 1).cgColor
self.button.borderColorAnimation(from: fromColor, to: toColor, duration: 200)
I did find the final answer.
Thanks to krotov who tried to help!
class BorderButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var colorPast: Bool = true
override var isHighlighted: Bool {
didSet {
if isHighlighted && colorPast {
borderDissapear(highlighted: isHighlighted)
colorPast = false
} else if !isHighlighted && !colorPast {
borderDissapear(highlighted: isHighlighted)
colorPast = true
}
}
}
func borderDissapear (highlighted: Bool) {
let animation = CABasicAnimation(keyPath: "borderColor")
animation.duration = 0.1
animation.autoreverses = false
animation.repeatCount = 1
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
if highlighted {
animation.fromValue = self.layer.borderColor?.copy(alpha: 1)
animation.toValue = self.layer.borderColor?.copy(alpha: 0.3)
} else if !highlighted {
animation.fromValue = self.layer.borderColor?.copy(alpha: 0.3)
animation.toValue = self.layer.borderColor?.copy(alpha: 1)
}
self.layer.add(animation, forKey: "borderColor")
}
}