Putting hard bounds on an animating view in iOS - ios

I've been exploring iOS animations and I'm trying to find out if there is a simple way to restrict animation movement to within a certain area. For example, lets say you are using a pan gesture recognizer to drag a UIView around the screen. Is there a simple way to enforce that the frame of the UIView does not move beyond a specified location?
The way i've currently been approaching it is to take the UIView, calculate the location of the edges, and within my handlePan method, simply return (ie don't adjust the center point) if the frame is touching the boundary. Is there a more elegant way to do this? Even if only along a single axis?
Thanks!

I actually am doing that in one project and basically well, I am using the "non elegant" way. I have a set of coordinates "boundaries" from which the view I am dragging should not pass. Although there better ways to do this than others. For instance for a smoother experience:
Compare the X axis independently for the Y axis. What I was doing in the beginning was to compare the X and the Y in the same if sentence.
Extra: Check this project to get some ideas.

Related

Is it possible to simulate gravity to an object / UIView in UIDynamicKit?

Without using SpriteKit, is it possible to simulate gravity for UIView object? What I'm trying to achieve is a center UIView with other object floating around it. Almost like planets around a Sun. And also have it attract and repulse from the center object.
I know you can add horizontal and vertical gravity to the superview.
Thanks!
The solution is to use UIAttachmentBehavior.
let attachment = UIAttachmentBehavior(item: node, attachedTo: self.ownerNode)
self.animator.addBehavior(attachment)
The above code will have the node objects attached to the self.ownerNode. I also added UISnapBehavior to self.ownerNode so that when dragged away from the center, the self.ownerNode will always snap back to the center and all have all other nodes follow it.
let snapCenter = UISnapBehavior(item: self.ownerNode, snapTo: self.view.center)
self.animator.addBehavior(snapCenter)
Another approach: Use a field.
UIKit Dynamics brought fields to the table sometime around iOS 9, I think.
Fields provide same, similar or unique vectors of "force" for all the positions within their... field of influence. Hence the name.
You can switch a field, so it's pushing at one moment, pulling at another, or even combine them, layer them and align them around a screen in regions of influence.
A single field can act like planetary gravitational force in the middle of your screen, making satellites move around it, fall into it, or be repelled away.
Fields are a very powerful feature of UIKit Dynamics, both in terms of creativity and influence. They're also remarkably efficient because they only act on those things you stipulate to be influenced by them. So whilst their field size might be large, and their functions determining positional influence complex, they're still very efficient.
You can read/watch/listen to more about them here:
https://developer.apple.com/videos/play/wwdc2015/229/

Interact with complex figure in iOS

I need to be able to interact with a representation of a cilinder that has many different parts in it. When the users taps over on of the small rectangles, I need to display a popover related to the specific piece (form).
The next image demonstrates a realistic 3d approach. But, I repeat, I need to solve the problem, the 3d is NOT required (would be really cool though). A representation that complies the functional needs will suffice.
The info about the parts to make the drawing comes from an API (size, position, etc)
I dont need it to be realistic really. The simplest aproximation would be to show a cilinder in a 2d representation, like a rectangle made out of interactable small rectangles.
So, as I mentioned, I think there are (as I see it) two opposite approaches: Realistic or Simplified
Is there a way to achieve a nice solution in the middle? What libraries, components, frameworks that I should look into?
My research has led me to SceneKit, but I still dont know if I will be able to interact with it. Interaction is a very important part as I need to display a popover when the user taps on any small rectangle over the cylinder.
Thanks
You don't need any special frameworks to achieve an interaction like this. This effect can be achieved with standard UIKit and UIView and a little trigonometry. You can actually draw exactly your example image using 2D math and drawing. My answer is not an exact formula but involves thinking about how the shapes are defined and break the problem down into manageable steps.
A cylinder can be defined by two offset circles representing the end pieces, connected at their radii. I will use an orthographic projection meaning the cylinder doesn't appear smaller as the depth extends into the background (but you could adapt to perspective if needed). You could draw this with CoreGraphics in a UIView drawRect.
A square slice represents an angle piece of the circle, offset by an amount smaller than the length of the cylinder, but in the same direction, as in the following diagram (sorry for imprecise drawing).
This square slice you are interested in is the area outlined in solid red, outside the radius of the first circle, and inside the radius of the imaginary second circle (which is just offset from the first circle by whatever length you want the slice).
To draw this area you simply need to draw a path of the outline of each arc and connect the endpoints.
To check if a touch is inside one of these square slices:
Check if the touch point is between angle a from the origin at a.
Check if the touch point is outside the radius of the inside circle.
Check if the touch point is inside the radius of the outside circle. (Note what this means if the circles are more than a radius apart.)
To find a point to display the popover you could average the end points on the slice or find the middle angle between the two edges and offset by half the distance.
Theoretically, doing this in Scene Kit with either SpriteKit or UIKit Popovers is ideal.
However Scene Kit (and Sprite Kit) seem to be in a state of flux wherein nobody from Apple is communicating with users about the raft of issues folks are currently having with both. From relatively stable and performant Sprite Kit in iOS 8.4 to a lot of lost performance in iOS 9 seems common. Scene Kit simply doesn't seem finished, and the documentation and community are both nearly non-existent as a result.
That being said... the theory is this:
Material IDs are what's used in traditional 3D apps to define areas of an object that have different materials. Somehow these Material IDs are called "elements" in SceneKit. I haven't been able to find much more about this.
It should be possible to detect the "element" that's underneath a touch on an object, and respond accordingly. You should even be able to change the state/nature of the material on that element to indicate it's the currently selected.
When wanting a smooth, well rounded cylinder as per your example, start with a cylinder that's made of only enough segments to describe/define the material IDs you need for your "rectangular" sections to be touched.
Later you can add a smoothing operation to the cylinder to make it round, and all the extra smoothing geometry in each quadrant of unique material ID should be responsive, regardless of how you add this extra detail to smooth the presentation of the cylinder.
Idea for the "Simplified" version:
if this representation is okey, you can use a UICollectionView.
Each cell can have a defined size thanks to
collectionView:layout:sizeForItemAtIndexPath:
Then each cell of the collection could be a small rectangle representing a
touchable part of the cylinder.
and using
collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
To get the touch.
This will help you to display the popover at the right place:
CGRect rect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
Finally, you can choose the appropriate popover (if the app has to work on iPhone) here:
https://www.cocoacontrols.com/search?q=popover
Not perfect, but i think this is efficient!
Yes, SceneKit.
When user perform a touch event, that mean you knew the 2D coordinate on screen, so your only decision is to popover a view or not, even a 3D model is not exist.
First, we can logically split the requirement into two pieces, determine the touching segment, showing right "color" in each segment.
I think the use of 3D model is to determine which piece of data to show in your case if I don't get you wrong. In that case, the SCNView's hit test method will do most of work for you. What you should do is to perform a hit test, take out the hit node and the hit's local 3D coordinate of this node, you can then calculate which segment is hit by this touch and do the decision.
Now how to draw the surface of the cylinder would be the only left question, right? There are various ways to do, for example simply paint each image you need and programmatically and attach it to the cylinder's material or have your image files on disk and use as material for the cylinder ...
I think the problem would be basically solved.

tracking camera's position and rotation

I have allowsCameraControl property set to true. I need my camera to tell me what it's position and rotation is, while I move it around with pinch and pan gestures so I can later update my camera to that position. Is there some function that is called every rendering moment so I can put println: statement in it? The other option I could think was to set a didSet statement at camera's position and rotation property but I have no idea how to do that if I'm not the one defining the property in the first place.
Found a way around it using custom buttons(moveLeft,moveRight,rotateLeft etc..) to move the camera(and report current position) around 3D space. Works great. Can't tell if mnuages's suggestion works, but it looks allright.
you can use delegation methods such as SCNSceneRendererDelegate's -renderer:didRenderScene:atTime: and you can access the "free" camera by using the view's pointOfView.

UIView perpetual linear animation with collision detection

I'm trying to make a circular UIView animate in a particular direction until it collides with the borders of the view (which is full screen, so basically the borders of the device), at which point it will reflect off it and continue on its way infinitely. However, I'm not really sure how to pose my question, so I'm having trouble finding any information on it. I already have the view, the direction it will move in, and its velocity. I'm just not sure how to handle an animation like that.
Any advice is much appreciated! Thanks!
Use a CADisplayLink to continuously update the position of the view, synced with the refresh rate of the screen. The update method that that display link triggers will take into account the current x and y velocity of the view and update the frame based on it. If at ever point the x- or y-coordinate goes under or over a limit (0 or screen width/height), reverse the appropriate velocity value and recalculate the position.

Getting the same coordinates from UIScrollView whether it's zoomed or not

Is it possible to get the same coordinates from UIScrollView whether it's zoomed or not.
That is, For example, consider a plain screen of 320.0F and 480.0F.
Tap on a point; view will give me something like (60.0F, 80.0F).
Zooming-in or zooming-out on the view so that it will have either bigger or smaller zoom scale but making sure the zoomed area to contain the point that was tapped which was (60.0F, 80.0F) according to previous zoom scale.
Tap on the point again, the view will give me different coordinate value.
The Thing is, I want to have the same coordinate value whether the view is zoomed or not. The idea is simple. I want to show images zoomed & interactive without changing its coordinate. Considering an UIScrollView applied of the idea with its height of 1.0 and width of 0.66, I think there would be some pros programming this way, when making an interactive app without using OpenGL, cocos2d or whatever 3D engines out there.
Do you guys have any idea if it's supported or not? Either case, please don't wait any second to reply. Thanks
You can calculate it by yourself using content size as follows,
x = (original_Width/ width_after_zooming) * point.x
y = (original_height/ height_after_zooming) * point.y

Resources