Trying to make UIImageView a circle and it appears twice - ios

I am trying to add an imageview as a circle in swift to a uiview. I call the following code in swift however it creates the image to appear briefly incorrectly before it is corrected to a circle
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
theirPicMaskFour.layer.cornerRadius = theirPicMaskFour.frame.height / 2
theirPicMaskFour.layer.masksToBounds = false
theirPicMaskFour.layer.borderWidth = 0;
theirPicMaskFour.clipsToBounds = true
}
The following is the way it looks initially.
The following is how it looks after.

Try
theirPicMaskFour.layer.cornerRadius = theirPicMaskFour.frame.size.width / 2
instead of
theirPicMaskFour.layer.cornerRadius = theirPicMaskFour.frame.height / 2

Try theirPicMaskFour.layer.masksToBounds = true and log out the height before u assign just to be sure that the height isn't something out of ordinary
[EDIT]
Alloc and init it in viewDidLoad but update the round rect in viewDidLayoutSubviews as it will be called multiple times, but changes on frames wont effect it as that will remain same.

Related

UIView Rotation using swift issue

I would like to rotate UIView which defined on the storyboard I used
CGAffineTransform(rotationAngle: self.degreesToRadians(5))
which degreesToradians a function to convert to Radians, the rotation is working perfectly but the only problem is the UIView not vectorial (the edge of the view is not rendered properly and it looks like a saw) like in the screenshot below :
I have had the same problems as you and to solve it I just add a border to the view which is transparent, do it like this:
customView.layer.borderWidth = 1
customView.layer.borderColor = UIColor.clear.cgColor // important that it is clear
customView.layer.shouldRasterize = true
customView.layer.rasterizationScale = UIScreen.main.scale
Add that code after your rotation code.
With the code:
Without the code:

How to clear and redraw contents of a UIView (present inside a view controller) with swift?

I've a UIView inside a View Controller in which I'm drawing few lines as required by my app. After a certain point of time, I want some of those lines to disappear and a few other to appear in the same view. Approach I'm using as of now is that I'm clearing the UIView and redrawing all the lines I want to draw in the updated view.
Can somebody tell me what's the right way to go about it? I've gone through various questions that sound similar but it hasn't helped much. Till now I've tried things like:-
outletView.setNeedsDisplay()
and
let context = UIGraphicsGetCurrentContext()
context?.clear(outletView.frame)
None of these seem to make any difference.
If I call viewDidLoad() again since all the lines are updated now. New lines to be drawn come up but the ones that were supposed to disappear don't go away. Variables for lines are updated correctly since other logic I have which checks line variable's values is working fine after the update is supposed to happen. Only problem is with the redraw part. In fact, if I understand this correctly, problem is only with cleaning the old uiview contents. If cleaning happens properly, redraw with viewDidLoad will show correct lines drawn.
P.S. I know that calling viewDidLoad() explicitly isn't a good practice. Hope to find a solution to this problem without having to call viewDidLoad again.
Maybe you could draw your lines in different layers of the view, delete the layer containing the lines that need to disappear and create a new layer for the new lines. You can draw in layoutSubviews() and use self.setNeedsLayout() when you need to update the view.
remove:
guard let sublayers = yourView.layer.sublayers else { return }
for layer in sublayers {
layer.removeFromSuperlayer()
}
add:
let linesPath = UIBezierPath()
let linesLayer = CAShapeLayer()
linesPath.move(to: CGPoint(x: 0, y: 0)
linesPath.addLine(to: CGPoint(x: 50, y: 100)
lineLayer.path = linesPath.cgPath
linesLayer.lineWidth = 1.0
linesLayer.strokeColor = UIColor.black
yourView.layer.addSublayer(linesLayer)

swift: cannot assign value of type UIView to type CGRect

In the for loop I am trying to place images from arrayOfImages in rectangles that I've created with CGRect.
But after that I want to use class MyClassView which inherits UIView, because I have there additional functions that I want to apply on my rectangle images that I've just created, but I am getting the error
cannot assign value of type UIView to type CGRect
let widthRect = 50
func createMyRects(){
let insetSize = CGRectInset(self.view.bounds, CGFloat(Int(widthRect)), CGFloat(Int(widthRect))).size
for i in 0...arrayOfImages.count-1{
let pointX = CGFloat(UInt(arc4random() % UInt32(UInt(insetSize.width))))
let pointY = CGFloat(UInt(arc4random() % UInt32(UInt(insetSize.height))))
let showImages = UIImageView(image: arrayOfImages[i])
let newFrame = CGRect(x: pointX, y: pointY, width: CGFloat(widthRect), height: CGFloat(widthRect))
//showImages.frame = newFrame
let newFrame2 = MyClassView(frame: newFrame)
showImages.frame = newFrame2 //here it says: cannot assign value of type UIView view to type CGRect
view.addSubview(showImages)
}
}
To fix the error you need to assign the frame of your UIView subclass to the frame.
showImages.frame = newFrame2.frame
Your variable names are a bit misleading.
Justin gave an answer that would let your code compile, but it still doesn't make sense. I assume that the MyClassView(frame: newFrame) bit is an intializer for a MyClassView object? Why in the world would you create a new view object only to take it's frame and assign it to another view, and then discard the newly created view?
Why do you need to create a MyClassView object at all? My guess is that you don't, and that you shouldn't. Get rid of the line that creates a MyClassView object entirely and just use the code you have commented out? (showImages.frame = newFrame).
Finally I've solved it. Just wanted to post the answer if someone else comes up with same problem. Previously i tried to assign images, which i made from one picture with function that sliced original picture, to bunch of rectangles that i created. But it didn't work because i didn't correctly make my class MojView. It inherited UIView, now it inherits UIImageView. Besides, i made a change in one line of code and the result is - rectangles are assigned with images and all of them can be dragged which was my intention when i created MojClass. Here is the code for both MojClass and the rest of app. MojClass: https://github.com/Vukovi/Ne-to/blob/master/README.md && Rest: https://github.com/Vukovi/ostatak/blob/master/README.md

Swift: Changing UIView frame but display doesn't update

I'm trying to dynamically resize the frame of a UIView. I can update the frame in the code and see that the values have changed, but the actual display never changes, even though I run setNeedsDisplay().
I'm following this post, where I define a new frame via CGRectMake, and then set the UIView's frame to this new frame. i.e., I'm doing this...
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
If I print out the value of the UIView's frame, I see that it's changing as I like. But the display (in the Simulator) never reflects these changes.
Any idea how to fix this?
Update: In greater detail: I'm trying to programmatically cover up one UIView with another. It's a horizontal "VU Meter", consisting of a base UIImageView showing a color gradient, that gets partially dynamically "covered" up by a UIView with a black background.
The UIImageView "VUBarImageView" is defined in StoryBoard and is subject to AutoLayout. The black UIView "VUBarCover" is defined purely programmatically, with no AutoLayout constraints.
Here's the relevant parts of the code for completeness... The trouble I'm having is in updateVUMeter()...
#IBOutlet weak var VUBarImageView: UIImageView!
var VUBarCover : UIView!
// this gets called after AutoLayout is finished
override func viewDidLayoutSubviews() {
// cover up VU Meter completely
let center = VUBarImageView.center
let width = VUBarImageView.frame.width
let height = VUBarImageView.frame.height
let frame = VUBarImageView.frame
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
VUBarCover.backgroundColor = UIColor.blueColor() // use black eventually. blue lets us see it for testing
}
// partially cover up VUBarImage with black VUBarCover coming from the "right"
func updateVUMeter(inputValue:Float) { //inputValue is in dB
//let val = pow(10.0,inputValue/10) // convert from dB
let val = Float( Double(arc4random())/Double(UInt32.max) ) //for Simulator testing, just use random numbers between 0 and 1
print("val = ",val)
let fullWidth = VUBarImageView.frame.width
let maxX = VUBarImageView.frame.maxX
let width = fullWidth * CGFloat(1.0-val)
let minX = maxX - width
let minY = VUBarImageView.frame.minY
let height = VUBarImageView.frame.height
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
VUBarCover.setNeedsDisplay()
print("fullWidth = ",fullWidth,"width = ",width)
print(" newFrame = ",newFrame,"VUBarCover.frame = ",VUBarCover.frame)
}
And sample results are:
val = 0.9177
fullWidth = 285.0 width = 23.4556210041046
newFrame = (278.544378995895, 93.5, 23.4556210041046, 10.0) VUBarCover.frame = (278.544378995895, 93.5, 23.4556210041046, 10.0)
val = 0.878985
fullWidth = 285.0 width = 34.4891595840454
newFrame = (267.510840415955, 93.5, 34.4891595840454, 10.0) VUBarCover.frame = (267.510840415955, 93.5, 34.4891595840454, 10.0)
val = 0.955011
fullWidth = 285.0 width = 12.8218790888786
newFrame = (289.178120911121, 93.5, 12.8218790888786, 10.0) VUBarCover.frame = (289.178120911121, 93.5, 12.8218790888786, 10.0)
...i.e., we see that VUBarCover.frame is changing 'internally', but on the screen it never changes. What we see instead is the full-size cover, completely covering the image below (ca. 300 pixels wide), even though its width should be only, about 12 pixels).
Even if I do a setNeedsDisplay() on the superview of VUBarCover, nothing changes.
Help? Thanks.
First, you have a few errors worth noting:
Instance variables (like VUBarCover and MainView should always begin with a lowercase letter (like mainView).
You should call super.viewDidLayoutSubviews() at the beginning of your override implementation
Second, viewDidLayoutSubviews() can be called any number of times, so your implementation of this method should be idempotent, meaning it has an identical effect no matter how many times it's called. But when you call:
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
You are creating a new UIView and adding it to the view hierarchy, along with the others you may have added in the past. So it looks like the frame isn't updating on the screen. In fact, you just can't tell because the old views are behind the one you're updating and they're not changing.
Instead, you probably want to create this once:
var vuBarCover = UIView()
Add it as a subview in viewDidLoad():
mainView.addSubview(vuBarCover)
And modify its frame in viewDidLayoutSubviews():
vuBarCover.frame = vuBarImageView.frame
You don't need to call setNeedsDisplay().
In my case, there were animations left on the layer, after removing them, the frame changes are updated:
myView.layer.removeAllAnimations()
iOS displays presentationLayer of a UIView on the screen, animations are played on that layer (frame updates goes there during animation).
I am making a custom UIView like you right now, maybe I can help.
Firstly, viewDidLayoutSubviews() like your comment: this gets called after AutoLayout is finished. And after every layout did set, you start to set new frame for your UIView and UIImage, maybe the bug is here. Please try to move your code in viewDidLayoutSubviews() to layoutSubviews(). And don't forget add super.layoutSubviews() in override function, which can help you away from hundreds of bugs :].
Secondly, only if you override the drawRect: method, then you should call setNeedsDisplay(), which is telling system that i need to redraw my view, and system will call drawRect: method appropriately.
Hope you can figure it out.

How to correctly set a circle imageView with Swift?

im trying to make a circle imageprofile, like the profile image of instagram/whatsapp. Right now my code seems to work, but i did it in 2 different ways and both works, so i want to know which one is the best
First way:
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
profileImageView.clipsToBounds = true
Second way
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
profileImageView.layer.masksToBounds = true
Also i would like if someone can explain me about "clipToBounds" and "maskToBounds", what they do. Thanks!
clipsToBounds is a boolean value that determines whether subviews are confined to the bounds of the view.
Setting this value to YES causes subviews to be clipped to the bounds of the receiver. If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is NO.
Basically, this thing plays with the view's property.
Whereas masksToBounds is a boolean indicating whether sublayers are clipped to the layer’s bounds.And this thing plays with the layer of the view.
The way that I always do it, specifically in a situation where I want to show a profile picture in my application, I use this code:
profileImage.layer.cornerRadius = self.profileImage.frame.size.width / 2;
profileImage.clipsToBounds = true;
This is what I would recommend to do!

Resources