Determining if UIView in array of UIView's overlap with each other at all, and then adjust position
Here's a quick option based on my comment above about moving the logic for comparing distance into creation of the random point:
This can be cleaned up, but I didn't want to fully rewrite it and used as much of your code as possible.
In the generateCirles
function I only changed how you init your CircleView
func generateCircles() {
numberOfCircles = Int.random(in: 1..<50)
let circleWidth = CGFloat(25)
let circleHeight = circleWidth
for _ in 0..<numberOfCircles {
let circleView = CircleView(frame: CGRect(origin: getRandomPoint(), size: (CGSize(width: circleWidth, height: circleHeight))))
let number = Int.random(in: 0..<2)
if number == 1 {
circleView.mainColor = .yellow
} else {
circleView.mainColor = .blue
}
circles.append(circleView)
}
drawCircles()
}
In the getRandomPoint
I added a check to see if the new point is a valid point based on your existing distance logic:
func getRandomPoint() -> CGPoint {
let viewMidX = self.circlesView.bounds.midX
let viewMidY = self.circlesView.bounds.midY
let xPosition = self.circlesView.frame.midX - viewMidX + CGFloat(arc4random_uniform(UInt32(viewMidX*2)))
let yPosition = self.circlesView.frame.midY - viewMidY + CGFloat(arc4random_uniform(UInt32(viewMidY*2)))
let point = CGPoint(x: xPosition, y: yPosition)
if !validatePoint(point) {
return getRandomPoint()
}
return point
}
func validatePoint(_ point: CGPoint) -> Bool {
for circle in circles {
if distance(circle.frame.origin, point) <= 25 {
return false
}
}
return true
}
And I removed all of your code from drawCircles
that you posted.
Here's what it looks like with 300 circles: (I used the view frame as the circlesView frame, so that's why the circles are over lapping with the screen bounds) This shouldn't be an issue for you, as I assume your circlesView frame is set to be smaller.
Choosing a random point within a circular image in a UIImageView
If you want to generate a random point in a circle, you would do better to pick your point in polar coordinates and then convert it to Cartesian.
The polar coordinate space uses two dimesions, radius and angle. Radius is just the distance from the center, and angle usually starts at "due east" for 0, and goes around counter-clockwise up to 2π (that's in radians, 360˚ of course in degrees).
Presumably your wheel is divided into simple wedges, so the radius actually doesn't matter; you just need to pick a random angle.
uint32_t angle = arc4random_uniform(360);
// Radius will just be halfway from the center to the edge.
// This assumes the circle is exactly enclosed, i.e., diameter == width
CGFloat radius = colorWheel.bounds.size.width / 4;
This function will give you a Cartesian point from your polar coordinates. Wikipedia explains the simple math if you're interested.
/** Convert the polar point (radius, theta) to a Cartesian (x,y). */
CGPoint poltocar(CGFloat radius, CGFloat theta)
{
return (CGPoint){radius * cos(theta), radius * sin(theta)};
}
The function uses radians for theta
, because sin()
and cos()
do, so change the angle to radians, and then you can convert:
CGFloat theta = (angle * M_PI) / 180.0
CGPoint randomPoint = poltocar(radius, theta);
One last step: this circle has its origin at the same place as the view, that is, in the corner, so you need to translate the point to use the center as the origin.
CGPoint addPoints(CGPoint lhs, CGPoint rhs)
{
return (CGPoint){lhs.x + rhs.x, lhs.y, rhs.y};
}
CGPoint offset = (CGPoint){colorWheel.bounds.size.width / 2,
colorWheel.bounds.size.height / 2};
randomPoint = addPoints(randomPoint, offset);
And your new randomPoint
will always be within the circle.
How to get random coordinates inside a swift UIView?
Your issue is with the line below
imageView.frame = self.view.convert(self.coinsView.frame, from: self.coinsView.superview!)
This line is setting the same frame of coinsView
to imageView
. And when you are trying to get random x and y points in the below code it will always return 0. because frame.size.width
and imageView.bounds.size.width
are same and same goes to height.
let x = randomInRange(lo: 0, hi: Int(frame.size.width - imageView.bounds.size.width))
let y = randomInRange(lo: 0, hi: Int(frame.size.height - imageView.bounds.size.height))
For better understanding add below line to your code to set imageView
Frame, you need to set static frame to your image view initially.
imageView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
Make sure width and height should be smaller than the width and height of coinsView's width & height
Set Uibutton Random Position on UIView
1st, add buttons to an NSArray, only to make things easier:
NSArray *buttonArray = @[btn1,btn2,btn3,btn4,btn5];
Now, this code tries to Arrange them at random positions.
int xTemp, yTemp;
for (int i = 0; i < 5; i++) {
while (YES) {
xTemp = arc4random_uniform(view.frame.size.width - [buttonArray[i] frame].size.width);
yTemp = arc4random_uniform(view.frame.size.height - [buttonArray[i] frame].size.height);
if (![self positionx:xTemp y:yTemp intersectsAnyButtonTillIndex:i inButtonArray:buttonArray]) {
[AnimationView moveBubble:CGPointMake(xTemp, yTemp) duration:1 : buttonArray[i]];
break;
}
}
}
Implement this function somewhere too:
- (BOOL) positionx:(int)xTemp y:(int)yTemp intersectsAnyButtonTillIndex:(int)index inButtonArray:(NSArray *)buttonArray {
//Again please change the < to <= , I'm sorry, doing too many things at once.
for (int i = 0; i <= index; i++) {
CGRect frame = [buttonArray[i] frame];
//EDIT : In the logic earlier, I had wrongly done a minus where I should have done a plus.
if ((xTemp > frame.origin.x && xTemp < (frame.size.width + frame.origin.x)) && (yTemp > frame.origin.y && yTemp < (frame.size.height + frame.origin.y))) return YES;
}
return NO;
OK this is a workign soln., I hope, just added something to WolfLink's answer. Check This.
for (UIButton *button in buttonArray) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
while ([self button:button intersectsButtonInArray:buttonArray]) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
}
//another function
-(BOOL)button:(UIButton *)button intersectsButtonInArray:(NSArray *)array {
for (UIButton *testButton in array) {
if (CGRectIntersectsRect(button.frame, testButton.frame) && ![button isEqual:testButton]) {
return YES;
}
}
return NO;
}
UIView absolute screen point
So I ended up using UITapGestureRecognizer instead and calculating the position like this:
CGPoint gestureViewLocation = [gesture locationInView:gesture.view];
CGPoint absoluteLocation = [gesture locationInView:self.parentViewController.view];
CGRect fromRect = CGRectMake(absoluteLocation.x-gestureViewLocation.x, //subtract to we get point relative to gesture view
absoluteLocation.y-gestureViewLocation.y, //subtract to we get point relative to gesture view
gesture.view.frame.size.width,
gesture.view.frame.size.height);
Related Topics
Finding It Difficult to Pass Data to Separate Viewcontroller
Different Cell in Tableview Swift 3
Avcapturestillimageoutput VS Avcapturephotooutput in Swift 3
How to Use Key-Value Coding in Swfit 4.0
Uitapgesturerecognizer Sender Is the Gesture, Not the UI Object
Disable Vertical Scroll in Uiscrollview Swift
How to Pass in a Void Block to Objc_Setassociatedobject in Swift
Timer Label Not Updated After Switching Views (Swift)
Swiftui Transition from Modal Sheet to Regular View with Navigation Link
Buttonwithtype' Is Unavailable: Use Object Construction 'Uibutton(Type:)
Shift Avplayer Captions When Subview Overlaps Them
Masked Uivisualeffectview Does Not Work on iOS 10
How to Programmatically Check and Open an Existing App in iOS 8
Output Video Size Huge Using Hevc Encoder on iOS
Custom Uitoolbar Too Close to the Home Indicator on iPhone X