How to make the width of the border the same after scaling? - ios

I set "borderwidth = 3" to the view. After I scaling, the border either became thicker or thinner.
before scaling (yellow border on the left photo)
after scaling( yellow border on the right photo)
enter image description here
How can I keep the width of the border fixed after I scale it?
I user this source on the GitHub
https://github.com/yokurin/DragRotateScaleView
And just add v.layer.borderWidth = 5
lazy var rect1: DragRotateScaleView = {
let v = DragRotateScaleView(frame: CGRect(x: 20, y: 100, width: 200, height: 200))
v.delegate = self
v.backgroundColor = UIColor.cyan
v.layer.borderColor = UIColor(red: 22/255, green: 22/255, blue: 22/255, alpha: 1).cgColor
v.layer.borderWidth = 5
return v
}()
Thank You!!

Just divide the border width by the scale and set that value to the borderWidth again.
Try this in a playground:
import UIKit
import PlaygroundSupport
// Save this values, you will use them.
let border: CGFloat = 3
let scale: CGFloat = 5
// Example views.
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .red
let secondView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
secondView.layer.borderColor = UIColor.yellow.cgColor
secondView.layer.borderWidth = border
view.addSubview(secondView)
// View scale transformation.
secondView.transform = CGAffineTransform(scaleX: scale, y: scale)
// IMPORTANT: Change the width of the border after the transformation.
secondView.layer.borderWidth = border / scale
// This is only for the playground.
PlaygroundPage.current.liveView = view

Related

How to add shadow only to top and bottom to UIVIEW in swift

I am new in swift and I am trying to add shadow to UIView.
My code is like this
ViewPay.layer.masksToBounds = false
ViewPay.layer.shadowRadius = 2
ViewPay.layer.shadowOpacity = 1
ViewPay.layer.shadowColor = UIColor.red.cgColor
ViewPay.layer.shadowOffset = CGSize(width: 0 , height:2)
but it is adding shadow to all side
How can I add shadow like this
One solution is, put your ViewPay inside a container UIView.
Set your ViewPay to leading and trailing edges of container view, and for top and bottom add some padding to show shadow.
Also set container view clipsToBounds equals to true.
I hope to help with the solution of your question. In case you wanted something simple to understand, and also following the tips. You create a large container and add the required views. A vertical view of the purple color, another horizontal that would be gray color and in the middle put an image, as I did in the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Big container
let container = UIView(frame: CGRect(x: self.view.bounds.width * 0.25, y: self.view.bounds.height * 0.5, width: 250, height: 290))
container.backgroundColor = .clear
self.view.addSubview(container)
//Purple view
let viewContainer = UIView(frame: CGRect(x: container.bounds.midX , y: 0, width: container.bounds.width * 0.89, height: container.bounds.height))
viewContainer.layer.anchorPoint.x = 1.0
viewContainer.backgroundColor = UIColor(displayP3Red: 158/255, green: 131/255, blue: 178/255, alpha: 1.0)
viewContainer.layer.cornerRadius = 8
viewContainer.clipsToBounds = true
container.addSubview(viewContainer)
//Gray view
let viewContainer2 = UIView(frame: CGRect(x: container.bounds.midX , y: container.bounds.midY, width: container.bounds.width * 0.93, height: container.bounds.height * 0.86))
viewContainer2.layer.anchorPoint.y = 1.0
viewContainer2.layer.anchorPoint.x = 1.0
viewContainer2.backgroundColor = UIColor(white: 0.5, alpha: 0.3)
viewContainer2.layer.cornerRadius = 5
viewContainer2.clipsToBounds = true
container.addSubview(viewContainer2)
//image
let imageView = UIImageView(frame: CGRect(x: container.bounds.midX, y: container.bounds.midY, width: container.bounds.width * 0.90, height: container.bounds.height * 0.90))
imageView.contentMode = .scaleToFill
imageView.layer.anchorPoint = CGPoint(x: 1.0, y: 1.0)
imageView.layer.cornerRadius = 10
imageView.clipsToBounds = true
imageView.image = UIImage(named: "image name")
container.addSubview(imageView)
}
}

IOS - How to create Facebook reaction bar with blur background?

Although it may not be the week to replicate some design of Facebook, I would like to be able to design my own version of the reaction indicator view below.
I have three UIImageViews lined in the same positions as above. The problem is that, unlike Facebook, the background color may change (i.e is on top of a UIBlurEffect) and therefore I am unable to set the border color to white.
I thought it would make sense to set the borderColor like so:
imageViewOne.layer.borderColor = UIColor.clear.cgColor
imageViewOne.layer.borderWidth = 2
However, the underlying imageViewTwo is displayed in the border instead of the background color.
So far, I have this:
Would appreciate some help/ideas on how to make this work - I'm thinking of masks but not sure whether a. this is the correct solution and b. how to achieve the desired effect. To clarify, I am not able to set the border color as a constant as it will change with the UIBlurEffect.
In my opinion, there are 2 way to resolve your problem.
Create and use clipped image for Wow and Love like below Love image.
Another way is using mask property of UIView. Creating a mask image and apply it for mask property.
Mask image looks like.
Code for applying mask.
let imvLoveMask = UIImageView.init(image: UIImage.init(named: "MASK_IMAGE_NAME"));
imvLoveMask.frame = CGRect.init(x: 0, y: 0, width: imvLove.frame.size.width, height: imvLove.frame.size.height);
imvLove.mask = imvLoveMask;
Both of 2 above way can help you achieve what you want in the question. Background of icons in below image is an UIVisualEffectView.
In my opinion, the first way with clipped image is better and faster because you don't need to apply mask for your imageView. But if you don't want to create a clipped image for some reason, you can use the second way.
For more detail, you can take a look at my demo repo
You need to clip part of the image in order to let underlying content be visible in the gaps between images. See playground sample.
Add smile_1, smile_2, smile_3 images to playground resources. I took emoji images from https://emojipedia.org/facebook/.
import UIKit
import PlaygroundSupport
class EmojiView: UIView {
var imageView = UIImageView()
var imageInset = UIEdgeInsets(top: 3.0, left: 3.0, bottom: 3.0, right: 3.0)
var shapeLayer = CAShapeLayer()
var overlap: CGFloat = 0.0 {
didSet {
self.updateShape()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// MARK: UIView
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = UIEdgeInsetsInsetRect(self.bounds, self.imageInset)
self.shapeLayer.frame = self.bounds
self.updateShape()
}
// MARK: Private
private func setup() {
self.addSubview(self.imageView)
self.layer.mask = self.shapeLayer
}
private func updateShape() {
let frame = self.bounds
let path = UIBezierPath(rect: frame)
// Cut off part of the image if overlap more then > 0
if 0 < self.overlap {
path.usesEvenOddFillRule = true
path.append(UIBezierPath(ovalIn: CGRect(x: -frame.width + self.overlap, y: 0.0, width: frame.width, height: frame.height)).reversing())
}
self.shapeLayer.path = path.cgPath
}
}
let overlap: CGFloat = 10 // Amount of pixels emojis overlap each other
// Create emoji views
let emojiView_1 = EmojiView(frame: CGRect(x: 5.0, y: 5.0, width: 40.0, height: 40.0))
emojiView_1.imageView.image = UIImage(named: "smile_1")
let emojiView_2 = EmojiView(frame: CGRect(x: emojiView_1.frame.maxX - overlap, y: 5.0, width: 40.0, height: 40.0))
emojiView_2.imageView.image = UIImage(named: "smile_2")
emojiView_2.overlap = overlap
let emojiView_3 = EmojiView(frame: CGRect(x: emojiView_2.frame.maxX - overlap, y: 5.0, width: 40.0, height: 40.0))
emojiView_3.imageView.image = UIImage(named: "smile_3")
emojiView_3.overlap = overlap
let holderView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: emojiView_3.frame.maxX + 5, height: 50.0))
// Add gradient layer
let gradientLayer = CAGradientLayer()
gradientLayer.frame = holderView.bounds
gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
holderView.layer.addSublayer(gradientLayer)
// Add emoji views
holderView.addSubview(emojiView_1)
holderView.addSubview(emojiView_2)
holderView.addSubview(emojiView_3)
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = holderView
use this :
self.imageViewOne.layer.cornerRadius = self.imageViewOne.layer.bounds.width/2
self.imageViewOne.layer.masksToBounds = true
Simple suggestion: As you are setting border color programatically, you have a control to change it, according to background color (if background color is solid (not a gradient)).
imageViewOne.layer.borderColor = imageViewOne.superview?.backgroundColor ?? UIColor.white
imageViewOne.layer.borderWidth = 2.0
Actually instead of masking, you can put your images in a view which has white background and round(set corner radius). Then you can put these views (which has white background and images in it) via settings their zPosition or on storyboard with view hierarchy.
I've prepared a little playground for you. You can see the result in the screenshot. I've put a view inside the containerViews instead you can use uiimageview etc. It's a bit ugly but solves your issue I guess it's up to you to decide how use it.
Here is the code, you can just copy and paste it to a new playground and test it.
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var mainContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 140, height: 80))
mainContainerView.backgroundColor = UIColor.white
var containerView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
containerView.backgroundColor = UIColor.white
containerView.layer.cornerRadius = containerView.frame.width / 2
var innerView = UIView(frame: CGRect(x: 10, y: 10, width: 60, height: 60))
innerView.backgroundColor = UIColor.red
innerView.layer.cornerRadius = innerView.frame.width / 2
containerView.addSubview(innerView)
var containerView2 = UIView(frame: CGRect(x: 60, y: 0, width: 80, height: 80))
containerView2.backgroundColor = UIColor.yellow
containerView2.layer.cornerRadius = containerView2.frame.width / 2
var innerView2 = UIView(frame: CGRect(x: 10, y: 10, width: 60, height: 60))
innerView2.backgroundColor = UIColor.green
innerView2.layer.cornerRadius = innerView2.frame.width / 2
containerView2.addSubview(innerView2)
containerView.layer.zPosition = 2
containerView2.layer.zPosition = 1
mainContainerView.addSubview(containerView)
mainContainerView.addSubview(containerView2)
PlaygroundPage.current.liveView = mainContainerView

Swift make border rof uiimageview outside

I want to make a border to imageview and here is my code
let view = UIImageView()
view.layer.borderWidth = 4
view.layer.borderColor = UIColor(red: 1, green: 1, blue: 1, alpha:0.4).cgColor
view.layer.cornerRadius = 40
view.layer.masksToBounds = true
But this only adds border inside of imageview,how can i make it outside?
This can help you. Add a border layer using CALayer you can customize border color and border frame, also the other parameters.
let borderLayer = CALayer()
let borderFrame = CGRect(x: -1.0, y: -1.0, width: imageView.frame.size.height + 2.0, height: imageView.frame.size.height + 2.0)
borderLayer.backgroundColor = UIColor.clear.cgColor
borderLayer.frame = borderFrame
borderLayer.cornerRadius = 5.0
borderLayer.borderWidth = 2.0
borderLayer.borderColor = UIColor.red.cgColor
imageView.layer.addSublayer(borderLayer)
There are 2 ways to do it.
1. Using storyboard
If you are doing it in the storyboard, you can give the layer related properties directly in User Defined Runtime Attributes column in the storyboard itself.
Screenshot:
2. Using Code
let imageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 240, height: 128))
imageView.image = UIImage(named: "Image")
imageView.layer.borderWidth = 4
imageView.layer.cornerRadius = 40
imageView.layer.borderColor = UIColor.red.cgColor
imageView.layer.masksToBounds = true
self.view.addSubview(imageView)
Output:
Edit:
Screenshot after changing alpha of borderColor
Create a UIView and make it slightly larger than the image, then add the image to the center. Setting the background color will make the border a different color.
let border = UIView(frame: CGRect(x: 0, y: 0, width: 251, height: 251))
border.backgroundColor = UIColor.red
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 250, height: 250))
image.center = border.center
image.image = ...
border.addSubview(image)

How can I add right border on an UIView on Swift 3?

I have an UIView on the top of my screen and I want to add a right border of 1 pixel to it.
Here is the code that I have by the moment:
var border = CALayer()
border.backgroundColor = UIColor(red: 241, green: 10, blue: 9, alpha: 1).cgColor
border.frame = CGRect(x: topView.frame.width + 1, y: 0, width: 1, height: topView.frame.height)
topView.layer.addSublayer(border)
but I am not able to get it work.
What can I do to add a right border to my UIView?
Thanks in advance!
This code works for me, You are setting the position of the frame outside of the bounds of the view, change it to - 1 (instead of width + 1) and then it should display as expected. (I changed the colours to make it easier to see in playground)
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = UIColor.white
let borderLayer = CALayer()
borderLayer.backgroundColor = UIColor.red.cgColor
borderLayer.frame = CGRect(x: view.frame.width - 1, y: 0, width: 1, height: view.frame.height)
view.layer.addSublayer(borderLayer)
Cliptobounds = false on topview or keep the line within the frame

How to add custom footer (with gradient) in ios 8 to UIView

I'm able to add a custom status bar (with gradient) to the UIView like this:
override func viewDidLoad() {
super.viewDidLoad()
var statusBar : UIView = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 20))
let statusBarGradient : CAGradientLayer = CAGradientLayer()
statusBarGradient.frame = statusBar.bounds
let cor1 = UIColor(red: 0.416, green: 0.604, blue: 0.796, alpha: 1.0)
let cor2 = UIColor.whiteColor()
let arrayColors = [cor1.CGColor, cor2.CGColor]
statusBarGradient.colors = arrayColors
view.layer.insertSublayer(statusBarGradient, atIndex:0)
}
I would also like to add the same gradient to the footer but I'm not having much luck.
Your code works if you add the statusBar as a subview of the view, but I would make it dynamically size the width to fit the width of the superview, so just do the same thing for the footer, but dynamically set the height to be whatever the height of your view is minus the desired height of your footer bar.
let statusBar = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 20))
let footer = UIView(frame: CGRect(x: 0, y: view.frame.height - 20.0, width: view.frame.width, height: 20))
let statusBarGradient = CAGradientLayer()
let footerGradient = CAGradientLayer()
statusBarGradient.frame = statusBar.bounds
let cor1 = UIColor(red: 0.416, green: 0.604, blue: 0.796, alpha: 1.0)
let cor2 = UIColor.blackColor()
let arrayColors = [cor1.CGColor, cor2.CGColor]
footerGradient.frame = footer.bounds
let arrayColorsFooter = [cor2.CGColor, cor1.CGColor]
statusBarGradient.colors = arrayColors
footerGradient.colors = arrayColorsFooter
statusBar.layer.insertSublayer(statusBarGradient, atIndex:0)
footer.layer.insertSublayer(footerGradient, atIndex:0)
view.addSubview(statusBar)
view.addSubview(footer)

Resources