Gradient background is not applied for navigation bar on iPhoneX.
This is my function code:
func setGradientBackground(Colors: [UIColor]) {
var updatedFrame = bounds
updatedFrame.size.height += self.frame.origin.y
if UIDevice().userInterfaceIdiom == .phone {
if UIScreen.main.nativeBounds.height == 2436{
updatedFrame.size.height += 44
} else {
updatedFrame.size.height += 20
}
}
let gradientLayer = CAGradientLayer(frame: updatedFrame, colors: Colors)
setBackgroundImage(gradientLayer.createGradientImage(), for: UIBarMetrics.default)
}
Here is the result for iPhoneX
Related
Green Image Place to Orange image exact match (x, y, width, height)
I try to move navigation bar titleView image to another image (Orange Image) with animation while user scrolling table view and when scroll up and down the put image to original place.
Sample Code
override func viewDidLoad() {
imgViewSmall = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: 44, height: 44))
imgViewSmall.backgroundColor = .green
self.navigationItem.titleView = imgViewSmall
imgView.backgroundColor = .orange
animator.pauseAnimation()
animator.addAnimations {
var smallSize = self.imgViewSmall.frame
let bigSize = self.imgView.frame
smallSize.size.width = bigSize.width
smallSize.size.height = bigSize.height
self.imgViewSmall.center = bigImageCoordinate
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let minHeight:CGFloat = 0.0
let maxHeight:CGFloat = 170.0
factor = ((scrollView.contentOffset.y - minHeight)) / (maxHeight - minHeight)
// update the new position acquired
self.lastContentOffset = scrollView.contentOffset.y
if factor == 0 {
//animator.stopAnimation(false)
}
else if factor == 1 {
//animator.stopAnimation(false)
}
else {
//animator.startAnimation()
animator.fractionComplete = factor
}
self.navigationItem.titleView?.setNeedsDisplay()
print("factor \(factor ?? 0)")
}
I am new to iOS.I want to apply gradient colors on CarbonTabSwipeNavigation.I tried to apply the gradient to the toolbar of CarbonTabSwipeNavigation, but it is not happening
I have tried with Static Colore Code
carbonTabSwipeNavigation.toolbar.isTranslucent = true
var color1 = hexStringToUIColor(hex: "#00275E")
carbonTabSwipeNavigation.carbonSegmentedControl?.backgroundColor = color1
carbonTabSwipeNavigation.setIndicatorColor(UIColor.white) //tabBar font
carbonTabSwipeNavigation.setSelectedColor(UIColor.white, font: UIFont.boldSystemFont(ofSize: 14))
First, add these extensions in your project.
extension UINavigationBar {
func setGradientBackground(colors: [UIColor]) {
var updatedFrame = bounds
updatedFrame.size.height += self.frame.origin.y
let gradientLayer = CAGradientLayer(frame: updatedFrame, colors: colors)
setBackgroundImage(gradientLayer.createGradientImage(), for: UIBarMetrics.default)
}
}
extension UIView {
func setGradientBackgroundOnView(colors: [UIColor]) {
var updatedFrame = bounds
// updatedFrame.size.height += self.frame.origin.y
let gradientLayer = CAGradientLayer(frame: updatedFrame, colors: colors)
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
extension CAGradientLayer {
convenience init(frame: CGRect, colors: [UIColor]) {
self.init()
self.frame = frame
self.colors = []
for color in colors {
self.colors?.append(color.cgColor)
}
startPoint = CGPoint(x: 0, y: 1)
endPoint = CGPoint(x: 1, y: 1)
}
func createGradientImage() -> UIImage? {
var image: UIImage? = nil
UIGraphicsBeginImageContext(bounds.size)
if let context = UIGraphicsGetCurrentContext() {
render(in: context)
image = UIGraphicsGetImageFromCurrentImageContext()
}
UIGraphicsEndImageContext()
return image
}
}
Then call this method as your requirement.
Example:- If you want to set a gradient color on navigationbar of your app then call use this
self.navigationController?.navigationBar.setGradientBackground(colors: [UIColor.black, UIColor.red])
I've got a view controller being pushed onto a navigation controller which is inside a tab bar controller. The view controller hidesBottomBarWhenPushed and on view will appear it shows a toolbar. No matter what I try, it won't stop animating the toolbar sliding up / down when the view controller is pushed or popped. This only seems to be an issue on the iPhone X. Does anyone know how work around it?
This answer https://stackoverflow.com/a/47225653/1211917 helps me:
class SafeAreaFixTabBar: UITabBar {
var oldSafeAreaInsets = UIEdgeInsets.zero
#available(iOS 11.0, *)
override func safeAreaInsetsDidChange() {
super.safeAreaInsetsDidChange()
if oldSafeAreaInsets != safeAreaInsets {
oldSafeAreaInsets = safeAreaInsets
invalidateIntrinsicContentSize()
superview?.setNeedsLayout()
superview?.layoutSubviews()
}
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
if #available(iOS 11.0, *) {
let bottomInset = safeAreaInsets.bottom
if bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90) {
size.height += bottomInset
}
}
return size
}
override var frame: CGRect {
get {
return super.frame
}
set {
var tmp = newValue
if let superview = superview, tmp.maxY !=
superview.frame.height {
tmp.origin.y = superview.frame.height - tmp.height
}
super.frame = tmp
}
}
}
I want to make a static progress bar with no animation at all. I just want the orange part to be filled like and this image shows progress of (1 of 3), I would like to know how to accomplish this view for (2 of 3) and finally completed progress bar as in (3 of 3).
Thank you and any help would be greatly appreciated.
Here you have a workin, designable class
import Foundation
import UIKit
#IBDesignable
class StaticLoad: UIView {
enum Progress {
case Empty
case Filled(num: Int)
case Full
}
#IBInspectable public var progressColor: UIColor? {
didSet {
updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
}
}
#IBInspectable public var nonProgressColor: UIColor = .gray {
didSet {
updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
}
}
#IBInspectable public var numberOfSteps: Int = 3 {
didSet {
redrawSteps(step: numberOfSteps)
updateColor(progressColor: progressColor ?? self.tintColor, nonProgressColor: nonProgressColor)
}
}
#IBInspectable public var filledProgess: Int = 1 {
didSet {
if filledProgess >= numberOfSteps {
filledProgess = numberOfSteps
progress = .Full
}
if filledProgess <= 0 {
filledProgess = 0
progress = .Empty
} else {
progress = .Filled(num: filledProgess)
}
updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
}
}
private var tip: CGFloat = 5
private var progress: Progress = .Empty
private var progressLayers: [CAShapeLayer] = []
private func updateColor(progressColor: UIColor, nonProgressColor: UIColor) {
switch progress {
case .Empty:
progressLayers.forEach { $0.fillColor = nonProgressColor.cgColor }
case let .Filled(num):
progressLayers.dropFirst(num).forEach { $0.fillColor = nonProgressColor.cgColor }
progressLayers.dropLast(progressLayers.count - num).forEach { $0.fillColor = progressColor.cgColor }
case .Full :
progressLayers.forEach { $0.fillColor = progressColor.cgColor }
}
}
private func redrawSteps(step: Int) {
progressLayers.forEach { $0.removeFromSuperlayer() }
progressLayers.removeAll()
if step == 0 {
let layer = CAShapeLayer()
layer.frame = self.bounds
progressLayers.append(layer)
} else {
var topLeft = CGPoint(x: 0, y: 0)
let cgStep = CGFloat(step)
let avaibleWidth = self.bounds.width - (2 * (cgStep - 1))
let spacePerStep = avaibleWidth / cgStep
let height = bounds.height
let halfHeight = height / 2
for i in 0..<step {
let layer = CAShapeLayer()
let bezier = UIBezierPath()
bezier.move(to: topLeft)
bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep, y: topLeft.y))
if i + 1 != step {
bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep + tip, y: topLeft.y + halfHeight))
}
bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep, y: topLeft.y + height))
bezier.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y + height))
if i != 0 {
bezier.addLine(to: CGPoint(x: topLeft.x + tip, y: topLeft.y + halfHeight))
}
bezier.close()
layer.path = bezier.cgPath
progressLayers.append(layer)
self.layer.addSublayer(layer)
topLeft.x = topLeft.x + spacePerStep + 2
}
}
}
override func layoutSubviews() {
redrawSteps(step: numberOfSteps)
updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
}
}
All you have to do is take a UIView from the storyboard and make the custom class StaticLoad. You can specify the number of bars in the progress bar by changing the numberOfSteps property either by code or by the storyboard, and the fill of the bar by filledProgress
If you want a bigger arrow, just change the tip property, or specify another path for the bezierPath.
If you don't know, the #IBDesignable (it is recommended that if a class is designable it should be put in another framework rather than the same project due to the continuous compilation) allows the storyboard to render the view and the #IBInspectable allow to set the variable through the storyboard.
This is a working not-optimized example.
I've experimented a little bit to copy (or at least to have a similar working example) the airbnb navigationBar. For those who doesn't know the app please see the following screenshots:
:
As you may see the navigationBar is at first hidden and then is behind the image but overlays the heading label. I really like the animation how the navigationbar transition smoothly to the front.
I thought to do this with
Hide navigationBar
At the exact position beginn with fading in the navigationBar: Make navigationBar transparent and the increase the alpha
At the end of the animation show the default navigationBar
The implementation looks like: https://github.com/mbecker/AirbnbCopy
import UIKit
private let kTableHeaderHeight: CGFloat = 300.0
private let kTableHeaderCutAway: CGFloat = 60.0
class MainViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var headerView: UIView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var parkHeading: UILabel!
#IBOutlet weak var parkImage: UIImageView!
var headerMaskLayer: CAShapeLayer!
// create background images for the navigation bar
var navBarImage = UIImage().imageWithColor(UIColor(red:0.11, green:0.64, blue:0.98, alpha:0.0))
var gradientImage32 = UIImage().imageWithColor(UIColor(red:0.11, green:0.64, blue:0.98, alpha:0.0))
let image = UIImage(named: "bg-addo")
let overlay: UIView = UIView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.height, 400))
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
// Adjust view
self.automaticallyAdjustsScrollViewInsets = false
// NavigationBar
let attrs = [
NSForegroundColorAttributeName : UIColor.blackColor(),
NSFontAttributeName : UIFont(name: "HelveticaNeue-Bold", size: 17)!
]
self.navigationController!.navigationBar.titleTextAttributes = attrs
self.navigationController!.navigationBar.hidden = true
self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Default)
self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Compact)
// self.navigationController!.navigationBar.shadowImage = UIImage()
self.navigationController!.navigationBar.barStyle = .Default
// Header
overlay.backgroundColor = UIColor(red:0.04, green:0.28, blue:0.44, alpha:0.4)
parkImage.addSubview(overlay)
parkImage.image = image?.imageWithAlpha(1)
headerMaskLayer = CAShapeLayer()
headerMaskLayer.fillColor = UIColor.blackColor().CGColor
headerView.layer.mask = headerMaskLayer
updateHeaderView()
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let heightShowNavBarStart = kTableHeaderHeight - kTableHeaderCutAway - parkHeading.frame.height - 66
let heightShowNavBarEnd = kTableHeaderHeight - kTableHeaderCutAway - 66
print("scrollView.contentOffset.y - \(scrollView.contentOffset.y)")
print("heightShowNavBarStart - \(heightShowNavBarStart)")
print("heightShowNavBarEnd - \(heightShowNavBarEnd)")
let base = parkHeading.frame.height
let counter = heightShowNavBarEnd - scrollView.contentOffset.y
var alpha = counter / base
var navigationBarHidden = false;
if(scrollView.contentOffset.y >= heightShowNavBarStart && scrollView.contentOffset.y <= heightShowNavBarEnd){
} else if (scrollView.contentOffset.y < heightShowNavBarStart ){
navigationBarHidden = true
alpha = 1
} else if(scrollView.contentOffset.y > heightShowNavBarEnd) {
navigationBarHidden = false
alpha = 0
}
print("alpha - \(alpha)")
print("navigationBarHidden - \(navigationBarHidden)")
self.navigationController!.navigationBar.hidden = navigationBarHidden
if(!navigationBarHidden && alpha == 0){
// Show navigationBar && hide headerView parkImage
parkImage.hidden = true
self.navigationController!.navigationBar.setBackgroundImage(nil, forBarMetrics: .Default)
self.navigationController!.navigationBar.setBackgroundImage(nil, forBarMetrics: .Compact)
self.navigationController!.navigationBar.barStyle = .Default
} else {
parkImage.hidden = false
parkImage.image = image?.imageWithAlpha(alpha)
navBarImage = UIImage().imageWithColor(UIColor(red:0.96, green:0.96, blue:0.98, alpha: 1 - alpha))
self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Default)
self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Compact)
overlay.backgroundColor = UIColor(red:0.04, green:0.28, blue:0.44, alpha: alpha * 0.4)
}
}
func updateHeaderView(){
let effectiveHeight = kTableHeaderHeight-kTableHeaderCutAway/2
var headerRect = CGRect(x: 0, y: -effectiveHeight, width: scrollView.bounds.width, height: kTableHeaderHeight)
if scrollView.contentOffset.y < -effectiveHeight {
headerRect.origin.y = scrollView.contentOffset.y
headerRect.size.height = -scrollView.contentOffset.y + kTableHeaderCutAway/2
}
headerView.frame = headerRect
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 0))
path.addLineToPoint(CGPoint(x: headerRect.width, y: 0))
path.addLineToPoint(CGPoint(x: headerRect.width, y: headerRect.height))
path.addLineToPoint(CGPoint(x: 0, y: headerRect.height-kTableHeaderCutAway))
headerMaskLayer?.path = path.CGPath
}
}
extension UIImage {
func imageWithColor(colour: UIColor) -> UIImage {
let rect = CGRectMake(0, 0, 1, 1)
// Create a 1x1 pixel content
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
colour.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
func imageWithAlpha(alpha: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
I think the animation is not very smooth and at some point the header image is not set back to the top of the screen.
Has anyone an idea how to create such an navigationBar?
This is exactly what you want you it allows you to create header bars with flexible heights. Often, this sort of UI paradigm is used to hide "chrome" and make room for more content as a user is scrolling.
https://github.com/bryankeller/BLKFlexibleHeightBar/