swift cannot show the view at bottom of imageview - swift

i'm trying to show a layout at from the bottom of an imageview to a predefined height. Unfortunately its shown at the top, not at the bottom. This is my code i have tried:
var frm: CGRect = firstImageOverlay.frame
frm.origin.x = frm.origin.x
frm.origin.y = frm.origin.y
frm.size.width = frm.size.width
frm.size.height = frm.size.height
firstImageOverlay.frame = frm
UIView.animate(withDuration: 0.5, animations: {
self.progressA.frame = CGRect(x: frm.origin.x, y: frm.origin.y, width: frm.size.width, height: self.firstImageOverlay.frame.height*CGFloat(0.4))
})
and here is the result of this code:
the light gray part shows the layout at the left imageview. this should be shown from the bottom till the defined height

iOS uses a reflected cartesian coordinate system with 0,0 in the top right and positive y pointing down and positive x pointing right, so when you draw at x: frm.origin.x, y: frm.origin.y you are saying draw from the top left down to the width and height.
You need to adjust your y coordinate down:
self.progressA.frame = CGRect(x: frm.origin.x, y: frm.origin.y + self.firstImageOverlay.frame.height*CGFloat(0.6), width: frm.size.width, height: self.firstImageOverlay.frame.height*CGFloat(0.4))

Related

Vision framework barcode detection region of interest not working

I am trying to decode barcodes that appear on a region of interest, that is 80% of the screen width and 20% of the screen height and centered on both directions (blue rectangle).
The camera pixel buffer is rotated right.
This is what Apple has to say about this orientation:
The (x,y) pixel coordinates of the origin point (0,0) represent the
top row and rightmost column, respectively. Pixel (x,y) positions
increase top-to-bottom, right-to-left. If an image is encoded with
this orientation, then displayed by software unaware of orientation
metadata, the image appears to be rotated 90° counter-clockwise. (That
is, to present the image in its intended orientation, you must rotate
it 90° clockwise.)
So, when I define the region of interest of my VNDetectBarcodesRequest I do like this:
lazy var barcodeRequest: VNDetectBarcodesRequest = {
let barcodeRequest = VNDetectBarcodesRequest {[weak self] request, error in
guard error == nil else {
print ("ERROR")
return
}
self?.classification(request)
}
barcodeRequest.regionOfInterest = CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.6)
If the bar code is inside the blue area and at any point above that, including anywhere on the area at the top of the blue area, it will detect. If the barcode is down the blue area, it will not detect anything.
Just making sure, if you look at regionOfInterest, the documentation says:
The rectangle is normalized to the dimensions of the processed image. Its origin is specified relative to the image's lower-left corner.
So the origin (0,0) is at the bottom left. With your current CGRect,
CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.6)
you are getting the expected result - "If the bar code is inside the blue area and at any point above that, including anywhere on the area at the top of the blue area, it will detect."
All you need to do is change the height from 0.6 to 0.2. You will want:
barcodeRequest.regionOfInterest = CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.2) /// your height is wrong
Just to chime in here for added clarity, cuz this was also tripping me up.
The documentation for regionOfInterest says:
The default value is { { 0, 0 }, { 1, 1 } }
Which I was also confusing for 2 points (a bottom left corner and a top right corner). But that last pair is supposed to be the normalized width and height; not a normalized coordinate.
// ❌
request.regionOfInterest = CGRect(x: 0.1, y: 0.4, width: 0.9, height: 0.6)
// ✔️
request.regionOfInterest = CGRect(x: 0.1, y: 0.4, width: 0.8, height: 0.2)

aniamte inputview left to right border bottom

I have created this width animation which creates a border-bottom for my TextField and I want to animate it so that when the user clicks on the TextField the CALayer goes from left to right and then appear. the problem is that the animation start from the center and then the width grows to each side while I want it to start from left to right... What am I missing ?
override func didAddSubview(_ subview: UIView) {
let shape = CALayer()
shape.frame = CGRect(x: 0, y: self.height, width: self.width, height: 1)
shape.frame.origin.x = 0
shape.backgroundColor = UIColor.red.cgColor
self.layer.addSublayer(shape)
let boundsAnim:CABasicAnimation = CABasicAnimation(keyPath: "bounds.size.width")
boundsAnim.fromValue = 0
boundsAnim.toValue = self.width
boundsAnim.duration = 2
shape.add(boundsAnim, forKey: "bounds.size.width")
}
Set the anchor point to the left side
shape.anchorPoint = CGPoint(x: 0, y: 0.5)

Central align subView

I'm trying to centre a UIView in another view (so like a pop up view), but whatever I do, I just cannot align it centrally!
func loadPopUpView() {
let customView = CGRect(x: view.center.x, y: view.center.y, width: 100, height: 100)
popUpView = UIView(frame: customView)
popUpView.backgroundColor = UIColor.black
view.addSubview(popUpView)
popUpView.isHidden = false
}
I've changed the background colour to black just so I know when it appears.
I cannot do this with storyboard because it's going on a tableView, so I'm trying to do it programmatically. Result Image
You also need to minus half value of your custom view height and width from x and y like below:
let customView = CGRect(x: view.center.x - 50, y: view.center.y - 50, width: 100, height: 100)
You are telling it to put top left corner in the center, hence you need to let it get half size in position.
let customView = CGRect(x: view.center.x-50, y: view.center.y-50, width: 100, height: 100)
Another solution is the use anchorpoints.
customView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
customView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
customView.heightAnchor.constraint(equalToConstant: 100).isActive = true
customView.widthAnchor.constraint(equalToConstant: 100).isActive = true
On CGRect(x:, y:, width:, height:), the point (x,y) is the origin. In iOS, that's the top left point.
On the CGRect doc:
In the default Core Graphics coordinate space, the origin is located
in the lower-left corner of the rectangle and the rectangle extends
towards the upper-right corner. If the context has a
flipped-coordinate space—often the case on iOS—the origin is in the
upper-left corner and the rectangle extends towards the lower-right
corner.
So to fix this:
let width = 100.0
let height = 100.0
let customViewFrame = CGRect(x: view.center.x - width/2.0, y: view.center.y - height/2.0, width: width, height: height)
Another solution would be to apply the center once the frame (especially the width/size) have been set.
let customViewFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
customViewFrame = view.center

Margin between images in UIScrollView

The effect I'm after: Having spacing between images that is only visible while scrolling (like the photos app).
A lot of old obj-c answers suggest extending the scroll view's bounds offscreen to make it page farther, and making this offscreen space the gap between images.
The documentation for pagingEnabled states:
If the value of this property is YES, the scroll view stops on
multiples of the scroll view’s bounds when the user scrolls.
So in trying to change the multiples value, I extended the scrollView's width, and left paging enabled. Yet no answers I implement page past the gap - they always leave it in view:
So if the scroll width is longer, why isn't it paging the proper distance?
let gapMargin = CGFloat(20)
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width + gapMargin, height: view.frame.height)
let exdScrollWidth = scrollView.frame.width
//1
let imageView1 = UIImageView()
imageView1.backgroundColor = UIColor.green
imageView1.frame = CGRect(x: 0, y: 0, width: exdScrollWidth - gapMargin, height: scrollView.bounds.size.height)
//2
let imageView2 = UIImageView()
imageView2.backgroundColor = UIColor.yellow
imageView2.frame = CGRect(x: exdScrollWidth, y: 0, width: exdScrollWidth - gapMargin, height: scrollView.bounds.size.height)
//3
let imageView3 = UIImageView()
imageView3.backgroundColor = UIColor.red
imageView3.frame = CGRect(x: exdScrollWidth * 2, y: 0, width: exdScrollWidth - gapMargin, height: scrollView.bounds.size.height)
scrollView.contentSize.width = exdScrollWidth * 3
scrollView.addSubview(imageView1)
scrollView.addSubview(imageView2)
scrollView.addSubview(imageView3)
As the docs tell you, one "page" width is the bounds width of the scroll view.
So let's say the images are 100 points wide. And let's say the space between the images is to be 10 points. Then:
The scroll view's width must be 110 points.
The spaces must be distributed 5 points on each side of each image, like this (supposing we have 3 images):
5pts - 100pts (im) - 10pts - 100pts (im) - 10pts - 100pts(im) - 5pts
This will cause each page to consist in a 100pt image with 5 pts of space on each side, a total of 110 pts, the width of the scroll view:
5pts - 100pts (im) - 10pts - 100pts (im) - 10pts - 100pts(im) - 5pts
| | | |
It turns out I had an equal widths constraint set up that I'd forgotten about. This meant the multiple by which the scrollview paged was fixed at the width of the superview.

Move NSButton swift

I have a NSButton named round, and I need to change its position according to the previous position, e.g. move it 100 pixels to the right. How to do that? I'm new to swift, so any help will be appreciated
You need to edit the frame of the button, basically changing the x
coordinate with 100 pixels to the right, that means increasing it by 100.
See the code below
var button = NSButton(frame: NSRect(x: 0, y: 0, width: 100, height: 50));
var frame = button.frame
frame.origin.x += 100
button.frame = frame