How do I style a button to have transparent text? - ios

I am currently working on a welcome page and I came across this interesting design:
I'm trying to make a button at the bottom with text that goes through the semi-transparent view behind it. I tried out the following code but it doesn't seem to be working:
let transparent = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
let semiwhite = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.15)
bottomView.backgroundColor = semiwhite
loginButton.backgroundColor = semiwhite
loginButton.setTitleColor(transparent, forState: .Normal)
loginButton.layer.cornerRadius = 10
loginButton.layer.masksToBounds = true
loginButton.layer.borderWidth = 2.5
loginButton.layer.borderColor = transparent.CGColor
Does anyone know how to do this?

I'd suggest that you don't want "transparent" text. Instead, you may want to think of this as a white view with a "mask" which is the outline of the text, allowing the image underneath to be revealed. This is complicated a bit because the mask is actually inverted from how we generally mask images (e.g., the "Sign in with Facebook" text is not the mask, but rather the white space around it is). But Core Graphics offer ways to do this very easily.
So, while it's probably easiest to create this graphic in your favorite image editing tool, if you wanted to do it programmatically, you could do something like the following in Swift 3 or later:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let image1 = maskedImage(size: button1.bounds.size, text: "Sign in with Facebook")
button1.setImage(image1, for: .normal)
let image2 = maskedImage(size: button2.bounds.size, text: "Sign-up with Email")
button2.setImage(image2, for: .normal)
}
func maskedImage(size: CGSize, text: String) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let context = UIGraphicsGetCurrentContext()
context?.scaleBy(x: 1, y: -1)
context?.translateBy(x: 0, y: -size.height)
// draw rounded rectange inset of the button's entire dimensions
UIColor.white.setStroke()
let pathRect = CGRect(origin: .zero, size: size).insetBy(dx: 10, dy: 10)
let path = UIBezierPath(roundedRect: pathRect, cornerRadius: 5)
path.lineWidth = 4
path.stroke()
// draw the text
let attributes: [NSAttributedStringKey: Any] = [
.font: UIFont.preferredFont(forTextStyle: .caption1),
.foregroundColor: UIColor.white
]
let textSize = text.size(withAttributes: attributes)
let point = CGPoint(x: (size.width - textSize.width) / 2, y: (size.height - textSize.height) / 2)
text.draw(at: point, withAttributes: attributes)
// capture the image and end context
let maskImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// create image mask
guard let cgimage = maskImage?.cgImage, let dataProvider = cgimage.dataProvider else { return nil }
let bytesPerRow = cgimage.bytesPerRow
let bitsPerPixel = cgimage.bitsPerPixel
let width = cgimage.width
let height = cgimage.height
let bitsPerComponent = cgimage.bitsPerComponent
guard let mask = CGImage(maskWidth: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel, bytesPerRow: bytesPerRow, provider: dataProvider, decode: nil, shouldInterpolate: false) else { return nil }
// create the actual image
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
UIGraphicsGetCurrentContext()?.clip(to: rect, mask: mask)
UIColor.white.withAlphaComponent(0.9).setFill()
UIBezierPath(rect: rect).fill()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// return image
return image
}
The technique to pay attention to here is the use of CGImage(maskWidth:...), which lets us create an image mask out everything except the white text and border that we drew. Then when we create the final image, we can clip it to this "image mask" with clip(to:mask:).
Generally, when we talk about masking images, we're masking them with UIBezierRect or other images (where a non-zero alpha channel reveals what should be masked and what shouldn't). But here we're masking using an Core Graphics "image mask", which gives us more control. For a discussion on the differences between masking with an image mask and masking with an image, see the Masking Images chapter of the Quartz 2D Programming Guide.
For Swift 2 rendition, see previous revision of this answer.

I would design the button in something like Adobe Fireworks, leaving the text transparent and then save it as a GIF.
You can then set it as the background to your button.

First thing you can set tintcolor as your desired color.
and if you are setting alpha to 0 then that means view is being hidden. so don't give alpha to 0.
You have option like, you can use clear color. so background color will show.
second thing if you want to use color then take white color with alpha 0.5 or other color with alpha 0.5 or 0.2 likewise don't take exact 0. it will make view invisible.
This was fundamental part. Now in your case you can do something like this,
for example your button size is 30 x 100 than you should take uiview as background with greater size of that button and set clear color as background color and add button on that view so border color or textcolor will automatically set like wise if you give clear color as tint or border.
another easy option is you can take image exactly matching with requirement and take imageview and set background to clear color and image as your image and add button on that image inplace off button with clear color and no text because text covers in image itself
hope this will help :)

Related

Constructing a png file out of multiple images and labels

I have a few UIImageViews and UILabels that you can drag around the screen in an editor.
The images are png's with a very high resolution (>2400px ) but on screen they might appear smaller.
I would like to produce a png file out of that screen ( which includes labels and images at certain positions), which will hold the actual sizes of these images (>2400px) .
If I just capture the screen programmatically (render), he will produce an image in the size of the screen, and it will not be transparent.
How can I construct the png file by my self by placing images and texts in whatever sizes and positions I want?
This for example :
if let image = UIImage(named: "example.png") {
if let data = UIImagePNGRepresentation(image) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
will not let you specify locations or add multiple images and texts to the file
Found a pretty simple and sweet way to do so, first you save in a dictionary all your screen elements, then you can simply add them to a file with :
let font = UIFont.boldSystemFont(ofSize: 160)
let showText:NSString = "hello world"
// setting attr: font name, color...etc.
let attr = [NSFontAttributeName: font, NSForegroundColorAttributeName:UIColor.blue]
// getting size
let sizeOfText = showText.size(attributes: attr)
let image = UIImage(named: "image.png")
let rect = CGRect(x: 0, y: 0, width: image!.size.width,height: image!.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), false, 0)
// drawing our image to the graphics context
image?.draw(in: rect)
// drawing text
showText.draw(in: CGRect(x: rect.size.width/2.0, y: rect.size.height/2.0, width: rect.size.width, height: rect.size.height), withAttributes: attr)
// getting an image from it
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()

How to tint an animated UIImageView?

I'm attempting to apply tint of a UIImageView consisting of programatically loaded animationImages. Currently using iOS 9.3.
I think I've tried every proposed solution found here for applying the tint including:
Setting the .renderMode on load with: let newImage: UIImage? =
UIImage(named: filename as
String)!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
Setting the tintView either in the Storyboard or programatically
with: zeroImageView.tintColor = UIColor.redColor()
Setting the image .renderMode through the UIImageView itself:
zeroImageView.image = zeroImageView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
Setting the UIImageView's renderMode through the Interface Builder
user defined runtime attributes: imageRenderingMode Number 2
The image sequence is of PNGs with transparency, so, I would like to re-colour the image and maintain the transparency.
I've had no luck and am sort of at a loss. Wondering if maybe these methods only work for a still UIAnimationView? Any help would be greatly appreciated, thanks!
Here's some code:
// Load all images
while let element = enumerator.nextObject() as? String {
if element.hasSuffix("png") {
let filename: NSString = "Digits/0/" + element
print(filename)
imageNames.append(filename as String)
let newImage: UIImage? = UIImage(named: filename as String)!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
images.append(newImage!)
zeroImageView.tintColor = UIColor.redColor()
}
}
// Make animated UIImageView
zeroImageView.userInteractionEnabled = false
zeroImageView.animationImages = images
zeroImageView.animationDuration = 2.0
zeroImageView.startAnimating()
zeroImageView.tintColor = UIColor.redColor()
Try this...
extension UIImage {
func image(withTint tint: UIColor) -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
let rect = CGRect(origin: .zero, size: size)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(.normal)
context.clip(to: rect, mask: cgImage)
tint.setFill()
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
If none of those worked the next step I would do is programmatically place an empty UIView on top of the UIImageView. First off, it would not interfere with anything going on in the UIImageView.
I would check out this tutorial here: http://www.apptuitions.com/programmatically-creating-uiview-uislider-uiswitch-using-swift/
this will teach you how to programmatically add a UIView to the storyboard. I would add this code in the viewDidLoad() method.
The main thing you need to change is the background color of the UIView. First you have to decide what the color of the tint (which from what I see in your code is red) and then explicitly change the 'Alpha' of the color so that it is barely showing. You change the 'Alpha' because that is basically the opacity of the color.
Hope this helps.

How can I change the color of the UITabBar top border by creating a UIImage programmatically?

From my understanding, the only way to change the color of the top border is to set the background image (320x49, with pixel line at top). It seems to me that this is the only way (please correct me if I'm wrong).
Is there a way to do this without using an image file? For example, someone helped me change the NavigationBar bottom border by creating a UIImage from code:
UINavigationBar.appearance().shadowImage = UIImage.colorForNavBar(UIColor.redColor())
extension UIImage {
class func colorForNavBar(color: UIColor) -> UIImage {
let rect = CGRectMake(0.0, 0.0, 1.0, 1.0)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
This solution actually works well; it changes the color of my bottom border.
I tried to apply this to the TabBar, but nothing changes at all.
UITabBar.appearance().shadowImage = UIImage.colorForNavBar(.redColor())
You've pretty much answered your own question. You can do the same thing with your UITabBar as you did with your UINavigationBar. If you want to change the shadow image (i.e. the "top border"), then you have to change the background image. Straight from Apple:
The custom shadow image for the tab bar. This attribute is ignored if the tab bar does not also have a custom background image. To set this attribute programmatically, use the shadowImage property.
In your own question you seem to be aware of this:
the only way to change the color of the top border is to set the background image (320x49, with pixel line at top)
Except that it's not the background image that has a line at the top. You just have to set the background image to anything, then you can set the shadow image to your preference.
If you open up the simple "tabbed application" template within Xcode, you'll find that adding these two lines of code (and your UIImage extension code) indeed work:
// White background with red border on top
UITabBar.appearance().backgroundImage = UIImage.colorForNavBar(.whiteColor())
UITabBar.appearance().shadowImage = UIImage.colorForNavBar(.redColor())
Here is the Swift 3 solution:
extension UIImage {
class func colorForNavBar(color: UIColor) -> UIImage {
let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
// Or if you need a thinner border :
// let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 0.5)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(color.cgColor)
context!.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
used with the code above in the viewDidLoad of the UITabBarController
UITabBar.appearance().backgroundImage = UIImage.colorForNavBar(color: .white)
UITabBar.appearance().shadowImage = UIImage.colorForNavBar(color: .red)
You need to provide an different image for UINavigationBar.appearance().backgroundImage.
For example:
UINavigationBar.appearance().backgroundImage = UIImage.colorForNavBar(.blackColor())
UINavigationBar.appearance().shadowImage = UIImage.colorForNavBar(.redColor())
Normally, the other answers got it right - you have to set both a background image and a shadow image. However, doing so will cause the bar to drop its translucency (blur); even if you set a transparent image, the bar will be transparent, not translucent.
We also had a similar need, but we wanted to preserve the translucency of the bar. Instead of setting a shadow image, we subclassed the bar, and put a hairline subview with a color we want. When the bar lays out its subviews, we set the frame of the hairline to be the width of the bar, and a pixel exactly.
See my GitHub demo project.
Here is a screenshot of the result:
After you include my subview in your project, just use the following line to set the color:
if let tabBar = tabBarController?.tabBar as? ColoredHairlineTabBar {
tabBar.hairlineColor = ... //Your color
}
What about simply subclassing UITabBar and adding a new sublayer to the view in layoutSubviews.
Swift example:
override func layoutSubviews() {
super.layoutSubviews()
let topBorder = CALayer()
let borderHeight: CGFloat = 2
topBorder.borderWidth = borderHeight
topBorder.borderColor = UIColor.redColor().CGColor
topBorder.frame = CGRect(x: 0, y: -1, width: self.frame.width, height: borderHeight)
self.layer.addSublayer(topBorder)
}
You don't need an extension to create an image of a certain size, UIImage has a perfectly good constructor for that.
To prevent losing the translucent blur, you can set the bar tint color instead of a background image. You can also use the screen scale to make sure the border is one pixel, like the original border was:
let hairlineHeight = CGFloat(1) / UIScreen.main.scale
tabBar.barTintColor = .white
tabBar.shadowImage = UIImage(color: .black, size: CGSize(width: 1, height: hairlineHeight))

How to change the color of the bottom border of UINavigationBar?

I read many threads, but none solved this question in a clear, consistent answer for the latest version of Swift.
For example, this question's top answer suggests UINavigationBar.appearance().setShadowImage(). However, such a method does not exist in the latest version of swift.
I don't want to hide the bottom border. I just want to change the color.
Additionally, it'd be great to be able to change the height, but I know I'm asking too much in one question.
Edit: I created a 2x1 pixel image and set it to the shadowImage, but the border remains unchanged:
UINavigationBar.appearance().barTintColor = UIColor.whiteColor()
UINavigationBar.appearance().shadowImage = UIImage(named: "border.jpg") //in my AppDelegate, for global appearance
Here's the image; it's really small:
SWIFT 2.x :
Out of convenience, I've extended UIImage() to allow me to essentially use it as a color with the code immediately below.
extension UIImage {
class func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRectMake(0, 0, 1.0, 0.5)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Next, you'll want to add the following lines to your code to adjust the viewController's UINavigationBar's shadow image, or color in this instance.
// Sets Bar's Background Image (Color) //
self.navigationController?.navigationBar.setBackgroundImage(UIImage.imageWithColor(UIColor.blueColor()), forBarMetrics: .Default)
// Sets Bar's Shadow Image (Color) //
self.navigationController?.navigationBar.shadowImage = UIImage.imageWithColor(UIColor.redColor())
SWIFT 3.x / 4.x :
Extension code:
extension UIImage {
class func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 0.5)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
NavigationBar code:
// Sets Bar's Background Image (Color) //
navigationController?.navigationBar.setBackgroundImage(UIImage.imageWithColor(color: .blue), for: .default)
// Sets Bar's Shadow Image (Color) //
navigationController?.navigationBar.shadowImage = UIImage.imageWithColor(color: .red)
Edit 1:
Updated extension code so you can adjust rect size without changing UIImage color opacity.
Edit 2:
Added Swift 3 + Swift 4 code.
Old UIKit setter methods like UISomeClass.setSomething(whatIWantToSet) have been reformulated so that you can directly set them with an = sign. So, in my example you would have to use UISomeClass.something = whatIWantToSet.
In your case, it's UINavigationBar.appearance().shadowImage = whatYouWantToSet.
A bit tricky solution, but it works with no coding and extensions needed. Just add in StoryBoard under your navigationBar a Progress View and set its color and height to whatever you like. If you want full border also set progress to 1.
So you will get a proper border for your navigation bar and an option to add progressView at any time as extra bonus.
I know, I know... it's kinda tricky, but programmers should be lazy, no?

How can I change the top border of my UITabBar?

I'd like the UITabBar to have a top border of width 5.0. The border should be yellow color.
I don't want any left/bottom/right borders.
The Tab Bar border should be flat (no shadows or anything like that).
How can I remove shadow (image) line?
You can hide the top border this way in your FirstViewController.swift:
self.tabBarController!.tabBar.layer.borderWidth = 0.50
self.tabBarController!.tabBar.layer.borderColor = UIColor.clear.cgColor
self.tabBarController?.tabBar.clipsToBounds = true
And result will be:
Before:
After:
Hope it helps.
EDIT:
You can set background image this way:
UITabBar.appearance().backgroundImage = UIImage(named: "yourImageWithTopYellowBorder.png")
If you want to completely remove tab bar, put this in your AppDelegate:
UITabBar.appearance().shadowImage = UIImage()
UITabBar.appearance().backgroundImage = UIImage()
This is how I get it done. I added a subview on top of the UITabBar.
let lineView = UIView(frame: CGRect(x: 0, y: 0, width:tabBarController.tabBar.frame.size.width, height: 1))
lineView.backgroundColor = UIColor.yellow
tabBarController.tabBar.addSubview(lineView)
This is the complete solution, compiled of different SO answers, that worked for me (Swift 3):
// The tabBar top border is done using the `shadowImage` and `backgroundImage` properties.
// We need to override those properties to set the custom top border.
// Setting the `backgroundImage` to an empty image to remove the default border.
tabBar.backgroundImage = UIImage()
// The `shadowImage` property is the one that we will use to set the custom top border.
// We will create the `UIImage` of 1x5 points size filled with the red color and assign it to the `shadowImage` property.
// This image then will get repeated and create the red top border of 5 points width.
// A helper function that creates an image of the given size filled with the given color.
// http://stackoverflow.com/a/39604716/1300959
func getImageWithColor(color: UIColor, size: CGSize) -> UIImage
{
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size.width, height: size.height))
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
// Setting the `shadowImage` property to the `UIImage` 1x5 red.
tabBar.shadowImage = getImageWithColor(color: UIColor.red, size: CGSize(width: 1.0, height: 5.0))
SWIFT 3
I needed border colors (and line colors and weights) to match other elements in my app, so this worked for me in my custom UITabBarController's viewDidLoad:
tabBar.layer.borderWidth = 0.3
tabBar.layer.borderColor = UIColor(red:0.0/255.0, green:0.0/255.0, blue:0.0/255.0, alpha:0.2).cgColor
tabBar.clipsToBounds = true
UIView *borderLine = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 5.0)];
borderLine.backgroundColor = [UIColor yellowColor];
[self.tabBarController.tabBar addSubview:borderLine];
This is the way to add border to a UITabBar which I follow.
It works cool.
Swift 4.2
self.tabBarController!.tabBar.layer.borderWidth = 0.50
self.tabBarController!.tabBar.layer.borderColor = UIColor.clear.cgColor
self.tabBarController?.tabBar.clipsToBounds = true
Just change border color as you want.
There is a property named shadowImage that was introduced in iOS 6. You can change this to change the top border. For example, you can use a 1x1px image with a single colour to change the top border to that colour:
UITabBar.appearance().shadowImage = UIImage(named: "TabBarShadow")
You can also set it as just UIImage() to completely remove the top border.
UITabBar.appearance().shadowImage = UIImage()
To answer your question of a 5px border, this can be done by using a 1x5px image. There does not appear to be a limit on the size of the image and it will just repeat (so you could have a dotted line for example by having a 4x5px image where the first 2x5px are black and the next 2x5px are transparent). Note that if you use this, it is outside the bounds of the UITabBar so content will go behind the image unless you change the view bounds.
It's a shadow image (property) of tabbar. Try following solutions and see.
** Swift **
//Remove shadow image by assigning nil value.
UITabBar.appearance().shadowImage = nil
// or
// Assing UIImage instance without image reference
UITabBar.appearance().shadowImage = UIImage()
** Objective-C **
//Remove shadow image by assigning nil value.
[[UITabBar appearance] setShadowImage: nil];
// or
// Assing UIImage instance without image reference
[[UITabBar appearance] setShadowImage: [[UIImage alloc] init]];
Here is apple guideline for shadowImage.
#available(iOS 6.0, *)
open var shadowImage: UIImage?
Default is nil. When non-nil, a custom shadow image to show instead of
the default shadow image. For a custom shadow to be shown, a custom
background image must also be set with -setBackgroundImage: (if the
default background image is used, the default shadow image will be
used).
Firstly create an extension of UIImage as follow
extension UIImage {
func createSelectionIndicator(color: UIColor, size: CGSize, lineWidth: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRect(x: 0, y: 0, width: size.width, height: lineWidth))
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
In your view controller add the following code.
let tabBar = self.tabBarController!.tabBar
tabBar.selectionIndicatorImage = UIImage().createSelectionIndicator(color: UIColor.blue, size: CGSize(width: tabBar.frame.width/CGFloat(tabBar.items!.count), height: tabBar.frame.height) , lineWidth: 5.0)
Just set the UITabBar backgroundImage and shadowImage to be clear color:
tabBar.shadowImage = UIImage.init(color: UIColor.clear)
tabBar.backgroundImage = UIImage.init(color: UIColor.clear)

Resources