I have this code:
func initPlaceHolder(width: CGFloat, height: CGFloat){
var firstPlaceHolderPosition: CGFloat = 0;
UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0)
let context = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: width, height: height)
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextSetStrokeColorWithColor(context, UIColor.blackColor().CGColor)
CGContextSetLineWidth(context, 1)
CGContextAddRect(context, rectangle)
CGContextDrawPath(context, .FillStroke)
let img = UIGraphicsGetImageFromCurrentImageContext()
for i in 1...4 {
let imageView = StompUIImageView(frame: CGRect(x: firstPlaceHolderPosition, y: 0, width: width, height: height))
let tap = UITapGestureRecognizer(target: self, action: "doubleTapped:")
tap.numberOfTapsRequired = 2
imageView.image = img
imageView.addGestureRecognizer(tap)
imageView.userInteractionEnabled = true
imageView.stompID = String(i)
imageView.stompSlot = i
addSubview(imageView)
firstPlaceHolderPosition = firstPlaceHolderPosition + width + 10
UIGraphicsEndImageContext()
}
}
func doubleTapped(sender: UITapGestureRecognizer) {
let view = sender.view as! StompUIImageView
print(view.stompID)
}
Basically the doubleTapped handler is called only for the first UIImageView and not for all 4.
Sorry being new to ios development I have difficulties to understand way.
Thanks for any help
Try this ...
Replace your code with this one....
I hope this will help you.
func initPlaceHolder(width: CGFloat, height: CGFloat){
var firstPlaceHolderPosition: CGFloat = 0;
UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0)
let context = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: width, height: height)
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextSetStrokeColorWithColor(context, UIColor.blackColor().CGColor)
CGContextSetLineWidth(context, 1)
CGContextAddRect(context, rectangle)
CGContextDrawPath(context, .FillStroke)
let img = UIGraphicsGetImageFromCurrentImageContext()
let tap = UITapGestureRecognizer(target: self, action: "doubleTapped:")
tap.numberOfTapsRequired = 2
for i in 1...4 {
let imageView = StompUIImageView(frame: CGRect(x: firstPlaceHolderPosition, y: 0, width: width, height: height))
imageView.image = img
imageView.addGestureRecognizer(tap)
imageView.userInteractionEnabled = true
imageView.stompID = String(i)
imageView.stompSlot = i
addSubview(imageView)
firstPlaceHolderPosition = firstPlaceHolderPosition + width + 10
UIGraphicsEndImageContext()
}
}
func doubleTapped(sender: UITapGestureRecognizer) {
let view = sender.view as! StompUIImageView
print(view.stompID)
}
My code was fine answering my own issue.
The problem was the line: addSubview(imageView)
I was adding 4 placeholder (about 300px) to a container smaller than the sum of the widths of all my placeholders.
Although I was seeing all the placeholders correctly displayed, the frame wasn't big enough to contain them and so the double tap not recognised.
Making the container bigger solved the issue.
Related
I have a code that adds an outline of the required width and color to an image and it works well
But I still need to adjust the rounding for the contour, please tell me in which direction should I start?
There are two functions here that do the job of laying the outline.
func colorized(with color: UIColor = .white) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
defer {
UIGraphicsEndImageContext()
}
guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
color.setFill()
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.clip(to: rect, mask: cgImage)
context.fill(rect)
guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return colored
}
/**
Returns the stroked version of the fransparent image with the given stroke color and the thickness.
- Parameters:
- color: The colors to user. By defaut, uses the ``UIColor.white`
- thickness: the thickness of the border. Default to `2`
- quality: The number of degrees (out of 360): the smaller the best, but the slower. Defaults to `10`.
- Returns: the stroked version of the image, or self if something was wrong
*/
func stroked(with color: UIColor = .red, thickness: CGFloat = 2, quality: CGFloat = 10) -> UIImage {
guard let cgImage = cgImage else { return self }
// Colorize the stroke image to reflect border color
let strokeImage = colorized(with: color)
guard let strokeCGImage = strokeImage.cgImage else { return self }
/// Rendering quality of the stroke
let step = quality == 0 ? 10 : abs(quality)
let oldRect = CGRect(x: thickness, y: thickness, width: size.width, height: size.height).integral
let newSize = CGSize(width: size.width + 2 * thickness, height: size.height + 2 * thickness)
let translationVector = CGPoint(x: thickness, y: 0)
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return self }
defer {
UIGraphicsEndImageContext()
}
context.translateBy(x: 0, y: newSize.height)
context.scaleBy(x: 1.0, y: -1.0)
context.interpolationQuality = .high
for angle: CGFloat in stride(from: 0, to: 360, by: step) {
let vector = translationVector.rotated(around: .zero, byDegrees: angle)
let transform = CGAffineTransform(translationX: vector.x, y: vector.y)
context.concatenate(transform)
context.draw(strokeCGImage, in: oldRect)
let resetTransform = CGAffineTransform(translationX: -vector.x, y: -vector.y)
context.concatenate(resetTransform)
}
context.draw(cgImage, in: oldRect)
guard let stroked = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return stroked
}
I tried many options but most of the answers are just adding a conerRadius to the UIImageView (this doesn't work)
How can I add padding between an UIImageView and its border?
Img.layer.cornerRadius = Img.bounds.width / 2
Img.layer.borderWidth = 2
Img.layer.borderColor = UIColor.blue.cgColor
Img.clipsToBounds = true
Like this:
As per the this link
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let image = UIImage(named: "imagename")!
let imageView = UIImageView(image: image.imageWithInsets(insets: UIEdgeInsetsMake(30, 30, 30, 30)))
imageView.frame = CGRect(x: 0, y: 0, width: 300, height: 400)
imageView.backgroundColor = UIColor.gray
imageView.layer.borderWidth = 2
imageView.layer.borderColor = UIColor.blue.cgColor
view.addSubview(imageView)
}
}
extension UIImage {
func imageWithInsets(insets: UIEdgeInsets) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(
CGSize(width: self.size.width + insets.left + insets.right,
height: self.size.height + insets.top + insets.bottom), false, self.scale)
let _ = UIGraphicsGetCurrentContext()
let origin = CGPoint(x: insets.left, y: insets.top)
self.draw(at: origin)
let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageWithInsets
}
}
For adding padding to the UIImage of UIImageView, use the below piece of code in Swift
let padding: CGFloat = 6
myImageView.contentMode = .scaleAspectFill
myImageView.image = UIImage(named: "myImage.png").resizableImage(withCapInsets: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), resizingMode: .stretch)
The code is added to Github to let you understand the real problem.
This is the hierarchy:
-- ViewController.View P [width: 375, height: 667]
---- UIImageView A [width: 375, height: 667] Name: imgBackground
[A is holding an image of size(1287,1662)]
---- UIImageView B [width: 100, height: 100] Name: imgForeground
[B is holding an image of size(2400,982)]
I am trying to merge A with B but the result is stretched.
This is the merge code:
func mixImagesWith(frontImage:UIImage?, backgroundImage: UIImage?, atPoint point:CGPoint, ofSize signatureSize:CGSize) -> UIImage {
let size = self.imgBackground.frame.size
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
backgroundImage?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
frontImage?.draw(in: CGRect.init(x: point.x, y: point.y, width: signatureSize.width, height: signatureSize.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
Note:
.contentMode = .scaleAspectFit
Code works but the result is stretched.
See this line in code, let size = self.imgBackground.frame.size – I need to change this to fix the problem. Find the origin of subview with respect to UIImage size
Here's the screenshot to understand the problem:
What should I do to get the proper output of merge function?
You have two bugs in your code:
You should also calculate aspect for document image to fit it into UIImageView. In mergeImages() replace:
img.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
with:
img.draw(in: getAspectFitFrame(sizeImgView: size, sizeImage: img.size))
When calculating aspect you center image horizontally/vertically if its width/height less then UIImageView width/height. But instead of comparing newWidth and newHeight you should compare factors:
if hfactor > vfactor {
y = (sizeImgView.height - newHeight) / 2
} else {
x = (sizeImgView.width - newWidth) / 2
}
Try bellow code it works for me, hope it works for you too,
func addWaterMarkToImage(img:UIImage, sizeWaterMark:CGRect, waterMarkImage:UIImage, completion : ((UIImage)->())?){
handler = completion
let img2:UIImage = waterMarkImage
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
UIGraphicsBeginImageContext(img.size)
img.draw(in: rect)
let frameAspect:CGRect = getAspectFitFrame(sizeImgView: sizeWaterMark.size, sizeImage: waterMarkImage.size)
let frameOrig:CGRect = CGRect(x: sizeWaterMark.origin.x+frameAspect.origin.x, y: sizeWaterMark.origin.y+frameAspect.origin.y, width: frameAspect.size.width, height: frameAspect.size.height)
img2.draw(in: frameOrig, blendMode: .normal, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if handler != nil {
handler!(result!)
}
}
//MARK - Get Aspect Fit frame of UIImage
func getAspectFitFrame(sizeImgView:CGSize, sizeImage:CGSize) -> CGRect{
let imageSize:CGSize = sizeImage
let viewSize:CGSize = sizeImgView
let hfactor : CGFloat = imageSize.width/viewSize.width
let vfactor : CGFloat = imageSize.height/viewSize.height
let factor : CGFloat = max(hfactor, vfactor)
// Divide the size by the greater of the vertical or horizontal shrinkage factor
let newWidth : CGFloat = imageSize.width / factor
let newHeight : CGFloat = imageSize.height / factor
var x:CGFloat = 0.0
var y:CGFloat = 0.0
if newWidth > newHeight{
y = (sizeImgView.height - newHeight)/2
}
if newHeight > newWidth{
x = (sizeImgView.width - newWidth)/2
}
let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight)
return newRect
}
I am trying to port an artificial horizon app I wrote for a PC in c# to swift. It has a bezel image which does not move and behind it is a horizon image which can move up and down behind the bezel. The "window" part of the bezel is yellow so in c# I just made the yellow opaque.
In swift I stated with the horizon inside of a UIScrollView but I'm not sure how to get that to work with a second image that should not scroll.
Not all that up to speed on this swift stuff, can someone point me in the right direction?
let view: UIView = UIView.init(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
let scrollView = UIScrollView.init(frame: view.bounds)
view.addSubview(scrollView)
let backImage: UIImage = fromColor(UIColor.redColor(), size: CGSize(width: 1000, height: 1000))
let backImageView: UIImageView = UIImageView.init(image: backImage)
scrollView.addSubview(backImageView)
scrollView.contentSize = CGSize.init(width: backImage.size.width, height: backImage.size.height)
let frontImage: UIImage = fromColor(UIColor.blueColor(), size: CGSize(width: 100, height: 100))
let layer: CALayer = CALayer.init()
layer.frame = CGRect.init(x: view.center.x - 50, y: view.center.y - 50, width: 100, height: 100)
layer.contents = frontImage.CGImage
view.layer.addSublayer(layer)
func fromColor(color: UIColor, size: CGSize) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, rect)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
fromColor is a helper method.
Result of the code
I want to globally change the navigation bar back button, so I have this:
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(-100, -5000), forBarMetrics: .Default)
var backImage: UIImage = UIImage(named: "BackButton")!
backImage = backImage.imageWithAlignmentRectInsets(UIEdgeInsetsMake(0, 0, 0, 20))
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
But the back image is too close to the left of the screen. How do I move it farther to the right?
Just adjust the actual image.
extension UIImage {
func imageWithInsets(insets: UIEdgeInsets) -> UIImage {
UIGraphicsBeginImageContextWithOptions(
CGSizeMake(self.size.width + insets.left + insets.right,
self.size.height + insets.top + insets.bottom), false, self.scale)
let context = UIGraphicsGetCurrentContext()
let origin = CGPoint(x: insets.left, y: insets.top)
self.drawAtPoint(origin)
let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageWithInsets
}
}
For Swift 4:
extension UIImage {
func withInsets(_ insets: UIEdgeInsets) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(
CGSize(width: size.width + insets.left + insets.right,
height: size.height + insets.top + insets.bottom),
false,
self.scale)
let origin = CGPoint(x: insets.left, y: insets.top)
self.draw(at: origin)
let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageWithInsets
}
}
You need to adjust the left position on UIEdgeInsetsMake.
You are already calling it here:
backImage = backImage.imageWithAlignmentRectInsets(UIEdgeInsetsMake(0, 0, 0, 20))
Like so:
backImage = backImage.imageWithAlignmentRectInsets(UIEdgeInsetsMake(0, -50, 0, 50))