iPhone/iPad circular intensity gauge control (image included) - iphone

I found this interesting interface(starts at 33 seconds http://vimeo.com/22946428 ), and would like to design something similar for my own apps. I'm particularly interested in the circular intensity gauge/knob control as on the attached image.
It has a very futuristic feel to it and should be fairly simple to implement using touchesMoved: gesture recognizer callback.
But in order to not-reinvent the wheel, are there any open source libraries that offer advanced UI capabilities, like the ones in the picture/video?
Update: Answer by Hubert demonstrates how to use single finger motion to rotate the dial. The second part of the puzzle is: how to fill the control with color?
I'm thinking of rotating a background color image, but a part of it has to be cut off or covered with something else to vary from an empty background to full. Maybe the cut out element (about 1 radian) may hide a set of fan-like segments that follow the finger and create an illusion of a continuously increasing or decreasing fill of the gauge. The 6 segments x,y would be continuously animating, positioning them in such a way as to cover only the required fraction of the control.

I dont think you will find that control exactly, but Here are a couple of links to working with and tutorials on rotary controls for iOS:
http://www.raywenderlich.com/9864/how-to-create-a-rotating-wheel-control-with-uikit
http://maniacdev.com/2012/02/tutorial-creating-a-one-figure-rotation-gesture-recognizer-for-a-rotary-knob-control-on-ios/
http://maniacdev.com/2011/12/open-source-libraries-for-easily-adding-rotary-knob-controls-in-your-ios-apps/

Here's an example of a circular progress view. Combined with a one finger rotary control, it creates a similar gauge to the one requested (simply overlay 2 controls on top of each other)
Then link the two controls with the rotation callback:
- (void) rotation: (CGFloat) angle
{
// calculate rotation angle
imageAngle += angle;
if (imageAngle > 360)
imageAngle -= 360;
else if (imageAngle < -360)
imageAngle += 360;
progress = imageAngle/360.0;
}
DACircularProgress view
+
OneFingerRotationGestrureRecognizer

Related

Dynamically control Unity Cinemachine vCams Blends: HOW?

I can't find how to constantly dynamically blend between 3 cameras (I call them middle, upper & lower) based on the rate and height of the hero, constantly.
When following the hero, the middle vCam is the main/base one, I'd like to proportionally blend through upper and lower vCams based on the height of the hero.
The player/hero can move rapidly between heights, so the blend should be weighted with eases. Which is a natural part of Cinemachine blends. And works. But it's like a switch, to me, at my current understanding of Cinemachine blends, rather than a constant dynamic blending based on height.
You may consider removing the upper and lower camera and do your own "Manual blending" with only the middle camera. Recently I've been using Cinemachine and I do something similar of what your desired result is.
Since I don't exactly know how do you want your camera to behave, I show you some of my manual blending I've done, explained:
//Camera Direction
//If I´m not in ground, and I've been on the air for a specific time
if (!onGround && timeSinceLastJump > cameraDelay)
{
//Moves the offset of the camera down to the maximum allowed y offset (In your case it would be where the lower camera is)
if (vcam.GetCinemachineComponent<CinemachineTransposer>().m_FollowOffset.y >= maxYOffset)
vcam.GetCinemachineComponent<CinemachineTransposer>().m_FollowOffset.y -= offsetYSensivity;
//It also zooms out up to a specified level
if (vcam.m_Lens.OrthographicSize < maxFOV)
vcam.m_Lens.OrthographicSize += camSensivity;
}
else
{
//Same but upwards
if (vcam.GetCinemachineComponent<CinemachineTransposer>().m_FollowOffset.y <= minYOffset)
vcam.GetCinemachineComponent<CinemachineTransposer>().m_FollowOffset.y += offsetYSensivity;
//Same but zooming in
if (vcam.m_Lens.OrthographicSize > minFOV)
vcam.m_Lens.OrthographicSize -= camSensivity;
}
This way you can use your player height in the conditions, at the cost of having to design well the camera logic.
Maybe this helps you in some way to do what you want.
From what I remember, you can define the blend style in the Cinemachine blend options. From the description, it seems that it is set to "Cut" when you probably want something similar to EaseIn/EaseOut. It even allows you to define your own custom blend between cameras if the default options do not work for you.
Take a look at the documentation for more details.

rotary dial - rotation limitation

I am making a vintage phone and got a working starting code where user moves his fingers over a UIImageView numbers and it rotates dial. It then moves it back to original position. See screenshot.
The three problems that I can't seem to figure out are;
How can I restrict user to rotate only in clockwise direction? Currently user can move it in any direction (clockwise and counter clockwise)
How can I detect which number that user selected? Meaning user touched 1 or 3 or 5? I need this info so that I can stop the rotation when that number reaches the bar on the right.
In my current code when I stop the rotation and let go of the circle, it moves back to it's place by moving back counter clockwise. It works well if I select 1,2,3,4 but for any number 5 and up the dial moves clockwise back to its original position. How can I force counter clockwise motion on touchesEnded?
Let’s assume that you’re talking about this gesture:
Source.
Build a single-touch rotation gesture recognizer. After building the gesture recognizer correctly, you can just look at the rotation and see what to do with the rotary pad.
There are several things you’ll consider when building a single-touch rotation gesture recognizer. If you look at UIRotationGestureRecognizer, it uses connection between two touches, backed by two fingers, to derive the current angle, then compares the angle to the previous angle, derived from an earlier touch change event, to see the delta.
Measuring the current angle
It takes two points to form a line and you need a line to know the angle. If you’re working with only one touch, you need an anchor point. There are many ways to send an anchor point to your gesture recognizer, and since you’re likely going to build a custom class, use delegation.
Accumulating rotation counts
If you simply note the angle and send off messages during touch changes, it’ll sometimes work. However, if you’d like to implement hysteresis (e.g. this rotary dial will only rotate once clockwise, then it tightens up), you’ll need to accumulate rotation counts for both clockwise and counter-clockwise directions.
Fortunately, you can assume that a) the touch events will not get dropped too often, and b) simply comparing the current angle against the past angle, seeing if they cross quadrant boundaries, will suffice.
For example:
If the touch moved from the top-left quadrant into the top-right quadrant, add one to the rotation count.
If the touch moved from the top-right quadrant into the top-left quadrant, subtract one from the rotation count.
(Yup, this actually works.)
Emitting the correct, accumulated rotation
If you want to emit rotation information exactly like how UIRotationGestureRecognizer did, there will be four things you’re tracking.
Starting Angle: The angle between a connection from the anchor point to the starting touch, and a connection from the anchor point to a fixed reference point.
Current Angle: The angle between a connection from the anchor point to the current touch, and a connection from the anchor point to a fixed reference point.
Rotation Count: The number of clockwise revolutions derived from continuously comparing the current value of Current Angle against its last value (as talked about in the last section). If the touch is moving counter-clockwise, then this count will go into negative.
You’ll provide Rotation Count * 2_PI + (Current Angle - Starting Angle) as the rotation.
OK, I would take a different approach. First, you want to create a RotaryDial class to encapsulate all of the behavior. Then you can just plug it into any view as you see fit.
To keep things simple I would consider making each number button a movable UIImageView, call it RotaryDialDigit or something like that. You would instantiate and place ten of those.
The dial "frame" would just tag along for the ride as the user moves one of the RotaryDialDigit buttons. It's just an image (unless you want the user to be able to touch it and do something with it.
From there, knowing which button is being held down and limiting its rotation to a given direction as well as stopping at at the bar is fairly easy stuff.
By using a protocol you can then have the RotaryDial instance tell the container when a number has been dialed. To the container RotaryDial would feel like a keypad sending a message every time a button is pressed. You really don't want the container bothering with anything other than completed number selections.
To detect which number is touched, when you create each number you should set the tag value of its UIView. Then when the user touches the number you can detect which UIView object it was by checking that tag value.
For the rotation problem, I'd suggest looking at how you are calculating the angle. At a guess I'd say for numbers greater than 4 (which you discern from the tag) you need to do something like subtract the angle you are currently calculating from 360 degrees (well 2Pi). (But I have a head cold right now so the actual math is escaping me :-) )
Without seeing your code, I assume the numbers are a static image and you are animating the finger holes as they rotate past each number. If so:
Detecting which number: defina a CGRect around each button. When the user taps the screen, check which rectangle contains the tap location.
Controlling rotation direction: as the user drags their finger, comtinuously calculate the angle from the dial stop to the current tap location. If the angle moves in the wrong direction, dont update the position of the finger hole. Note that trig functions return vales from +Pi to -Pi radians. For the digits greater than 5, rather than handle negative angles you will probably want to add 2Pi radians ( or 360 degrees) to the angle.
Rotating wrong way: the digits below 5 are generatting angles in the range of 0 to -Pi. Without seeing code, I suspect adding 2Pi to the angle will correct your rotation direction.
Here is a better dial:
Have fun!

iPhone 3D compass

I am trying to build an app for the iPhone 4 which enables the user to "point" at a hardcoded destination and a dot appears where the destination is located.
First, i use the compass to make a horizontal compass(this will cover the left/right rotation):
// Heading
nowHeading = heading.trueHeading;
// Shift image (horizontal compass)
float shift = bearing - nowHeading;
destinationImage.center = CGPointMake(shift+160, destinationImage.center.y);
I shift the dot 160 pixels because the screen is 320 pixels width. My question is now, how can I expand this code to handle up and down? Meaning that if i point the phone down in the table, the dot wont show.. I have to point (like taking a picture) at the destination in order for it to be drawn on the screen. I've already implemented the accelerator. But i don't know how to unite these components to solve my problem.
Bearing should depend on the field of vision of the camera. For iPhone 4 the horizontal angular view is 47.5 so 320 points/47.5 = xxx points per degree, use that to shift horizontally. You also have to add an adaptive filter to the accelerometers, you can get one from the AccelerometerGraph project from Apple.
You have the rotation in one axis (bearing) you should get the rotation on the other two from the accelerometers. The atan2 of two axis give you the rotation on the third. Go to UIAcceleration and imagine an axis physically piercing the device if that helps and do double xAngle = atan2(acceleration.y, acceleration.z); So once you have the rotation upside down you can repeat what you did for the horizontal with the vertical field of view, eg: 60 for the iPhone.
That is going to be one rough implementation :) but achieving smooth movement is difficult. One thing you can do is use the gyros to get a faster response and correct their signal periodically with the accelerometers. See this talk for the troubles ahead: Sensor Fusion on Android Devices. Here is a website dedicated to the Kalman Filter. If you dare with Quaternions I recommend "Visualizing Quaternions" from Andrew J. Hanson.
It sounds like you are trying to do a style of Augmented Reality. If that. Is the case there are several libraries and sample code suggested here:
Augmented Reality

How to detect a circle motion with UIGestureRecognizer

I want to be able to detect someone's finger drawing a circular motion on the screen - as if they were drawing an 'O'. Is this possible with UIGestureRecognizer?
I think the answer to this depends on your definition of circular motion and how you intend to use it. For example, do you want to know how many degrees along a circle the users finger has travelled? Or, do you only care about a circle being completed? What is the degree of accuracy you require? Do you want to allow for the motion to be interrupted or does this have to be more of a touch-down > draw-circle > touch-up (in other words, single motion)?
One approach would be to define a bunch of rectangular zones along the circumference and detect if the user is touching these in sequence. This can provide you with direction and a coarse indication of angle.
Another approach is to store the points between touch down and touch up and do some filtering and curve fitting to figure out what shape is approximated by the points. First low-pass-filter using a basic FIR filter and then look at the dx and dy from point to point. A circle (as a series of arcs) will have to fall within a certain range of slope changes from point to point, otherwise you have some other shape.
Yet another approach is to use a Neural Network to take the points and tell you what the shape looks like.
I think this may be what you need
How to detect circular gesture via Gesture Recognizer?
Instead using a gesture recognizer, this project reacts to circular motions tracking the angle of UITouch events.
My answer to my question:
I used this: http://iphonedevelopment.blogspot.com/2009/04/detecting-circle-gesture.html
.. but turned the CircleView into a custom UIGestureRecognizer. Everything lovely.
No, it doesn't recognize natively a circular motion.
You have to implement your own method to do that.
Here's how i needed to do it using the touches callbacks in my view controller but this could be made into a gesture too. Note, I was trying to detect multiple circle motions (2 or more clockwise or counterclockwise circles made during a touch event.
Store touchesMoved CGPoints in an array.
Create a min/max rect of all the points in your history array.
Divide this min/max rect into 4 smaller rects.
Assign each history point a quadrant using CGRectContainsPoint() for each of the 4 quadrants
A clockwise motion will have quadrants ascending. A counter-clockwise motion will have quadrants descending.
Check the ratio of width/height if you want to detect circles vs ovals

Animation with control re-use

I need to animate controls by moving them along the x axis from x to x-1000.
My container view is 200 pixels across and each control is 100 pixels wide.
There is a maximum of 4 controls (the controls are heavy and I need to re-use them)
So therefore, as I animate the controls from x to x-1000, I need to re-use them.
So as control 1 goes off to the left, it becomes invisible and needs to be re-positioned to the right hand side of the container view.
As I will be using an ease in function, the control needs to inherit the same speed and deceleration is it had before; so it literally just animates from right to left, once off screen, instantly re-positioned to the right of the container view, and carries on animating from right to left at the same deceleration rate.
Is there anyway to invoke a function for each frame of a CAPropertyAnimation? or something along those lines?
As far as I know, you can't get velocity information from core animation.
You will have to roll your own animation for this. Setup a timer, and give each view an xVelocity. Every time the timer fires, have it adjust the xVelocity of all objects (you could apply a sine curve to it to give it an ease/out effect). Then change the center point of all the objects.