uchicago-mobi / 2016-Winter-Forum

Class Forum for MPCS51030.
3 stars 0 forks source link

Real Circle Views #200

Closed aaizuss closed 8 years ago

aaizuss commented 8 years ago

Is anyone able to host office hours tomorrow (Wednesday)?

Is it possible to subclass UIView so that its bounds are actually a circle? My app uses 2 circle views, and I want to be able to move a small dot around (using a UIPanGestureRecognizer) within the circle view. Even though the views look like circles, the bounds of the view are still square. As a result, you can move the dot around outside of the circle (as long as its within the bounds of the square view that I used to draw the UIBezierPath in my drawRect function). Also, is there a way to add these custom views to the main view in the ViewController programmatically? (I couldn't get drawRect and an init function to work together) Right now I added them by dragging 2 UIViews to the storyboard and changing the class to the class that I made, and I access them in my ViewController with IBOutlets.

Even though I made the circle view fills UIColor.clearColor(), they show up as white over the app's background color: screen shot 2016-03-01 at 10 18 47 pm

More background: (for context, but it is likely confusing) My app uses a custom circle view (the UIView subclass is called CirclePickerView and it overrides drawRect). The circle view is hidden until you tap the view (well, this is the behavior I want, but I haven't been able to implement it successfully yet (see my note at the bottom of this issue (good luck) (nested parentheses, yay))). At the center of the hidden circle view is a much smaller circle (basically a dot) to indicate to the user that s/he should tap it. I want this dot to be visible even when the circle view is hidden and to be able to use the circle view center coordinates to place the dot. Tapping anywhere within the circle view makes the circle view visible. The circle view has a small UIView as a subview, which I call dotView (because it looks like a dot, but this is different from the small circle that is visible when the circle view is hidden that i mentioned earlier). I made a pan gesture recognizer so you can drag the dotView around within the circle. (except that functionality isn't working properly - it lets you drag around the whole view and when you let go it doesn't let you drag it again, for some reason) Tapping the circle view will hide the circle view again, reverting it to the original state of a hidden view with the dot in the middle.

This app will have 2 of these circle views, but they will never both be visible at the same time. When you open the app, you can see the 2 dots: 1 towards the top of the screen, and one towards the bottom of the screen. These dots are positioned to be in the center of where the circles would be if they were visible. When you tap one of the visible dots (for example, the one at the top of the screen), the circle view will become visible over that dot. When you tap anywhere in that circle view, the the circle view will hide itself. The other way to hide the currently visible circle view is to tap the dot from the currently hidden circle view (in this example this would mean tapping the dot at the bottom of the screen).

*I've added a tap gesture recognizer to each circle view, and I have a function didTapCircleView(sender: UITapGestureRecognizer) that sets circleView = sender.view and attempts to adjust circleView, but for some reason this circleView is a regular UIView instead of my custom class CirclePickerView. It's annoying because I specifically (programmatically) added a tap gesture recognizer to my CirclePickerView outlet so I don't see why sender.view returns type UIView and not CirclePickerView. This is important because when I try to adjust the alpha property of the UIView that it returns (in an attempt to make the circle visible), nothing actually happens to the CirclePickerView that I want it to change.

bobby-digital-23 commented 8 years ago

Sorry, I can't do office hours tomorrow but I will have two sessions on Thursday. Will post exact times soon.

susanstevens commented 8 years ago

@aaizuss I can't do office hours on Wednesday either, but I'll have my usual session on Sunday.

As far as making a circular view goes -- no, you can't make the bounds of the view a circle. However, since you know the center and radius of your circle, you can calculate whether or not a given point is inside the circle. If the point to which the user has panned is inside the circle, move the dot accordingly. If it's outside the circle, return from the gesture handling function without moving the dot.

You should definitely be able to add a custom view programmatically, whether or not it overrides drawRect. (My favorite way of creating a circle, however, is to set the cornerRadius of the view's layer to frame.width / 2. You can set the background color of the view and the borderColor and borderWidth of the layer if you want, all without using drawRect.)

Your tap gesture recognizer doesn't return a CirclePickerView because it doesn't know what a CirclePickerView is. If you need a CirclePickerView, you can cast sender.view to a CirclePickerView: if let circleView = sender.view as? CirclePickerView { ... }. However, I'm not sure why setting the alpha property on sender.view doesn't work. There could be something else going wrong here.

aaizuss commented 8 years ago

@susanstevens that helps a lot! I fixed it! (and thanks for reading my essay haha) screen shot 2016-03-02 at 12 28 12 am

aaizuss commented 8 years ago

@susanstevens Actually, do you know how to make the draggable dot snap to the boundary of the circle view if I try to drag it out? (I'm not sure if snap is the right term - the idea is that if I try to drag the dot outside of the circle, it stays along the circumference of the circle as I move my finger).

Here's what I have screen shot 2016-03-02 at 12 43 57 am

At this point, when I drag the dot outside of the view (which it lets me do), and let go, I can't drag the dot anymore (I don't know what that is...)

Edit I'm writing a function to check that a point is in a circle (obviously using the CGRectContainsPoint won't work)

tabinks commented 8 years ago
let touchPoint = where you finger is
if touchPoint.distanceFromCenter > radius of circle {
  return 
 // don't update the position
} else {
// do whatever you want to do with the new position
}

Essentially, you are disallowing anything to happen if you finger is outside the circle.

aaizuss commented 8 years ago

@tabinks Thanks! That mostly fixed my issue. It's a little fidgety (the circle where the dot is draggable appears to be slightly shifted compared to the circle that I can see on the screen), but I'll show you at office hours.