Need help on rotating image view with animation on orientation change (4 side rotation) in android - screen-orientation

i have a image view and i need to rotate(with IOS like animation) the image view on orientation change in android(portrait,landscape,reverse portrait and reverse landscape).
please advice
void rotateAndSet(int angle) {
if (currentAngle != angle || currentImage != currentBaseImage) { // This
// is
// to
// remove
// unnecessary
// drawing
currentAngle = angle;
currentImage = currentBaseImage;
myImg = decodeBase64(currentBaseImage);
matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotated = Bitmap.createBitmap(myImg, 0, 0, myImg.getWidth(),
myImg.getHeight(), matrix, true);
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
param.addRule(RelativeLayout.ALIGN_PARENT_TOP);
/*RotateAnimation animation = new RotateAnimation(0, 90,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setInterpolator(new LinearInterpolator());
animation.setFillAfter(true);
animation.setDuration(800);
ivFullScreen.startAnimation(animation); */
ivFullScreen.setLayoutParams(param);
ivFullScreen.setImageBitmap(rotated);
}
}

i got it
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
RotateAnimation animation = null;
if (event.values[0] < 4 && event.values[0] > -4) {
if (event.values[1] > 0 && orientation != ExifInterface.ORIENTATION_ROTATE_90) {
// UP
orientation = ExifInterface.ORIENTATION_ROTATE_90;
Log.i("testme","up");
animation = getRotateAnimation(0);
degrees = 0;
} else if (event.values[1] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_270) {
// UP SIDE DOWN
Log.i("testme","up side down");
orientation = ExifInterface.ORIENTATION_ROTATE_270;
animation = getRotateAnimation(180);
degrees = 180;
}
} else if (event.values[1] < 4 && event.values[1] > -4) {
if (event.values[0] > 0 && orientation != ExifInterface.ORIENTATION_NORMAL) {
// LEFT
Log.i("testme","left");
orientation = ExifInterface.ORIENTATION_NORMAL;
animation = getRotateAnimation(-270);
degrees =-270;
} else if (event.values[0] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_180) {
// RIGHT
Log.i("testme","right");
orientation = ExifInterface.ORIENTATION_ROTATE_180;
animation = getRotateAnimation(270);
degrees = 270;
}
}
if (animation != null) {
ivFullScreen.startAnimation(animation);
}
}
}
}

Related

Rotate unity gameobject smoth in the other direction

i want to rotate (actually just to the left and right side) an object by swiping over the screen. I have working code already but when i swipe from the left to the right of my screen, the whole movement is kind of lagging.
The object has the following script.
Any help is appreciated... this is driving me crazy.
Thank you for your time!
[ICODE]void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Debug.Log("Dragging Detected");
Vector2 newTouchPosition = Input.GetTouch(0).position;
float dis = (Vector2.Distance((Vector2)oldTouchPositions[0], newTouchPosition)) / 4;
if (((Vector2)oldTouchPositions[0])[0] < newTouchPosition[0])
{
//Debug.Log("Left"); dunno if correct
vertical = (vertical - velcoidadeDeGiro * dis) % 360;
transform.localRotation = Quaternion.AngleAxis(vertical, Vector3.up);
oldTouchPositions[0] = newTouchPosition;
}
else
{
//Debug.Log("Right");
vertical = (vertical - velcoidadeDeGiro * dis) % 360;
transform.localRotation = Quaternion.AngleAxis(vertical, Vector3.down);
oldTouchPositions[0] = newTouchPosition;
}
}
}[/ICODE]

touchCount difficulty on Android

This could be because I've been testing on a UnityRemote, however I'm trying to restart my main scene by touching with more than one finger on an android. endCondition is a variable I set as active when the player has been destroyed. Here is what my code looks like. All I want to do is restart the scene with multi-touch. Neither of the prints logged to the console so I doubt the multiple touches are being recognized. Here is my code that is inside of Update()
if (endCondition && (Input.touchCount > 1))
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch t = Input.GetTouch(i);
if (t.phase == TouchPhase.Began)
{
print("Made it here");
}
if (t.phase == TouchPhase.Ended)
{
print("Made it here");
SceneManager.LoadScene("Main");
}
}
}
This should fix it:
if (endCondition)
{
int fingersAmount = Input.touchCount;
//1 FINGER
if (fingersAmount == 1)
{
Touch t = Input.GetTouch(fingersAmount - 1);
if (t.phase == TouchPhase.Began)
{
Debug.Log("ONE FINGER");
}
if (t.phase == TouchPhase.Ended)
{
Debug.Log("ONE FINGER END");
//SceneManager.LoadScene("Main");
}
}
//2 FINGERS
else if (fingersAmount == 2)
{
Touch t = Input.GetTouch(fingersAmount - 1);
if (t.phase == TouchPhase.Began)
{
Debug.Log("TWO FINGERS");
}
if (t.phase == TouchPhase.Ended)
{
Debug.Log("TWO FINGERS END");
//SceneManager.LoadScene("Main");
}
}
//3 FINGERS
else if (fingersAmount == 3)
{
Touch t = Input.GetTouch(fingersAmount - 1);
if (t.phase == TouchPhase.Began)
{
Debug.Log("THREE FINGERS");
}
if (t.phase == TouchPhase.Ended)
{
Debug.Log("THREE FINGERS END");
//SceneManager.LoadScene("Main");
}
}
}

Drag and drop in unity 2d

I am trying to implement drag and drop functionality for my game in unity 2d. I have multiple copies of same object in my screen and they differ only by collider name. I attached the same script to them. Here is a piece of my code
function Start () {
playerTouches = [-1, -1];
}
function resetPlayer(touchNumber: int) {
for(var i = 0; i < playerTouches.length; ++i) {
if(touchNumber == playerTouches[i]) {
playerTouches[i] = -1;
}
}
}
function getCollider(vec: Vector2) {
var ray : Ray = Camera.main.ScreenPointToRay(vec);
var hit : RaycastHit2D = Physics2D.Raycast(ray.origin, ray.direction);
if (hit) {
if (hit.collider != null) {
Debug.Log(hit.collider.name);
return hit.collider.name;
} else {
Debug.Log("is null");
return "null";
}
} else {
Debug.Log("empty");
return "";
}
return "";
}
function processTouch(touch: Touch, touchNumber: int) {
if(touch.phase == TouchPhase.Began) {
var colliderName: String = getCollider(touch.position);
if(colliderName == "Object01" && playerTouches[0] == -1) {
playerTouches[0] = touchNumber;
} else if(colliderName == "Object02" && playerTouches[1] == -1) {
playerTouches[1] = touchNumber;
}
} else if(touch.phase == TouchPhase.Moved) {
// get object and change coords
} else if(touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled) {
resetPlayer(touchNumber);
}
}
function Update() {
if(Input.touchCount > 0) {
//Debug.Log("count = " + Input.touchCount);
for(var i = 0; i < Input.touchCount; i++)
{
processTouch(Input.GetTouch(i), i);
//Debug.Log("touch : " + i + " " + Input.GetTouch(i).position);
}
}
}
For now I'm detecting on which object user touch. I need to be able to get that object and change it's position.
I also found this code snippet which allows to move rigidbody
var touchDeltaPosition: Vector2 = touch.deltaPosition;
var touchPosition: Vector2;
touchPosition.Set(touchDeltaPosition.x, touchDeltaPosition.y);
rigidbody2D.transform.position = Vector2.Lerp(transform.position, touchPosition, Time.deltaTime * spd);
but it moves all objects regardless of what object I select.
Well, you can do like this. If you have 12 copies of same object and want to move the object which selected by user. So when user Touches the object Change that GameObject tag or Name to another tag. Afterward you can use the some Conditional Statement to work with your code.
Example :
if(Input.GetMouseButtonDown(0)) {
Debug.Log("Mouse is down");
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo = new RaycastHit();
//bool hit = Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hitInfo);
if(Physics.Raycast(ray, out hitInfo, 30)) {
Debug.Log("Hit " + hitInfo.transform.gameObject.name);
if(hitInfo.transform.gameObject.tag == "Deselected") {
//Debug.Log ("It's working! Attaching MoveCube Script to game :" + hitInfo.transform.gameObject.tag);
findObject = GameObject.FindGameObjectsWithTag("Deselected");
foreach(GameObject go in findObject) {
//go.gameObject.renderer.material.color = Color.white;
go.GetComponent<MoveCube>().enabled = false;
if(hitInfo.transform.gameObject.name.Equals(go.gameObject.name)) {
//hitInfo.transform.renderer.material.color = Color.white;
hitInfo.transform.gameObject.GetComponent<MoveCube>().enabled = true;
changeTAG = true;
} else {
hitInfo.transform.gameObject.tag = "Deselected"
}
}
playerObject = GameObject.FindGameObjectsWithTag("Player");
foreach(GameObject game in playerObject) {
count++;
if(count == 1) {
hitInfo.transform.gameObject.tag = "Player";
}
if(count >= 1) {
game.gameObject.tag = "Deselected";
game.gameObject.GetComponent<MoveCube>().enabled = false;
//game.gameObject.renderer.material.color = Color.white;
}
}
if(changeTAG) {
hitInfo.transform.gameObject.tag = "Player";
/*if (hitInfo.transform.gameObject.GetComponent<Rigidbody> ()) {
Debug.Log ("RigidBody is already added Can't add another RigidBody");
hitInfo.transform.rigidbody.WakeUp ();
} else {
hitInfo.transform.gameObject.AddComponent<Rigidbody> ().useGravity = false;
// hitInfo.transform.gameObject.GetComponent<Rigidbody> ().WakeUp ();
}*/
changeTAG = false;
} else if(!changeTAG) {
hitInfo.transform.gameObject.tag = "Deselected";
}
} else {
Debug.Log("Not Working");
}
} else {
Debug.Log("No hit");
}
Debug.Log("Mouse is down");
}
The above code is for Change the tag for selected and deselected cube. After that you can easily identify the Selected gameObject and can move it where ever you want.
You can use this code in the Update function.

Limiting JASidePanel Center panel slide

Hi I am using JASidePanels to create the left menu style but I want to do some particular changes.
The first is that I want the menu to have only 115 px wide. And for that I have found:
self.leftFixedWidth = 115;
Ok but, I can still slide the center panel to the right and see whats "hidden". Is there a way to fix its maximum position at 115 px? Just like the facebook menu?
go to JASidePanelController.m
find - (CGFloat)_correctMovement:(CGFloat)movement; method, replace it with this:
- (CGFloat)_correctMovement:(CGFloat)movement {
CGFloat position = _centerPanelRestingFrame.origin.x + movement;
if (self.state == JASidePanelCenterVisible) {
if (self.state != JASidePanelLeftVisible) {
if (position >= self.leftVisibleWidth) {
return self.leftVisibleWidth;
}
}
else if ((position > 0.0f && !self.leftPanel) || (position < 0.0f && !self.rightPanel)) {
return 0.0f;
}
} else if (self.state == JASidePanelRightVisible && !self.allowRightOverpan) {
if ((position + _centerPanelRestingFrame.size.width) < (self.rightPanelContainer.frame.size.width - self.rightVisibleWidth)) {
return 0.0f;
} else if (position > self.rightPanelContainer.frame.origin.x) {
return self.rightPanelContainer.frame.origin.x - _centerPanelRestingFrame.origin.x;
}
} else if (self.state == JASidePanelLeftVisible && !self.allowLeftOverpan) {
if (position > self.leftVisibleWidth) {
return 0.0f;
} else if (position < self.leftPanelContainer.frame.origin.x) {
return self.leftPanelContainer.frame.origin.x - _centerPanelRestingFrame.origin.x;
}
}
return movement;
}

iOS device orientation disregarding orientation lock

I want to query the orientation the iPhone is currently in. Using
[UIDevice currentDevice].orientation
works as long as the device isn't orientation-locked. If it is locked, however, it always responds with the locked orientation, not with the actual orientation of the device.
Is there a high-level way to get the actual device orientation?
Also you can use CoreMotion
Orientation detection algorithm:
if abs( y ) < abs( x ) your iPhone is in landscape position, look sign of x to detect right
or left
else your iPhone is in portrait position, look sign of y to detect up or upside-down.
If you are interested in face-up or down, look value of z.
import CoreMotion
var uMM: CMMotionManager!
override func
viewWillAppear( p: Bool ) {
super.viewWillAppear( p )
uMM = CMMotionManager()
uMM.accelerometerUpdateInterval = 0.2
// Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
// Dispatch U/I code to main thread using dispach_async in the handler.
uMM.startAccelerometerUpdatesToQueue( NSOperationQueue() ) { p, _ in
if p != nil {
println(
abs( p.acceleration.y ) < abs( p.acceleration.x )
? p.acceleration.x > 0 ? "Right" : "Left"
: p.acceleration.y > 0 ? "Down" : "Up"
)
}
}
}
override func
viewDidDisappear( p: Bool ) {
super.viewDidDisappear( p )
uMM.stopAccelerometerUpdates()
}
That functionality is correct. If it always returned the device orientation, even if it was locked, the orientation changed notifications would fire. This would defeat the purpose of the lock.
To answer your question, there is no way to read the raw values from the accelerometer, without using private APIs.
Edit:
After reviewing the documentation, it seems that the UIAccelerometer class provides this data, even when the orientation is locked. This change was applied in iOS 4 and above. Even though you can use this data, you still need to process it to determine the orientation. This is not an easy task as you need to monitor the changes constantly and compare them to older values.
Also, take a look at this guide for handling motion events. This may provide you with another route to determining the orientation.
Set up your view controller or whatever to support the UIAccelerometerProtocol, and start listening for changes (you can set it to 10 hz).
#define kAccelerometerFrequency 10.0 //Hz
-(void)viewDidAppear:(BOOL)animated {
DLog(#"viewDidAppear");
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
a.updateInterval = 1 / kAccelerometerFrequency;
a.delegate = self;
}
-(void)viewWillDisappear:(BOOL)animated {
DLog(#"viewWillDisappear");
UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
a.delegate = nil;
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
#ifdef DEBUG
+(NSString*)orientationToText:(const UIInterfaceOrientation)ORIENTATION {
switch (ORIENTATION) {
case UIInterfaceOrientationPortrait:
return #"UIInterfaceOrientationPortrait";
case UIInterfaceOrientationPortraitUpsideDown:
return #"UIInterfaceOrientationPortraitUpsideDown";
case UIInterfaceOrientationLandscapeLeft:
return #"UIInterfaceOrientationLandscapeLeft";
case UIInterfaceOrientationLandscapeRight:
return #"UIInterfaceOrientationLandscapeRight";
}
return #"Unknown orientation!";
}
#endif
#pragma mark UIAccelerometerDelegate
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
UIInterfaceOrientation orientationNew;
if (acceleration.x >= 0.75) {
orientationNew = UIInterfaceOrientationLandscapeLeft;
}
else if (acceleration.x <= -0.75) {
orientationNew = UIInterfaceOrientationLandscapeRight;
}
else if (acceleration.y <= -0.75) {
orientationNew = UIInterfaceOrientationPortrait;
}
else if (acceleration.y >= 0.75) {
orientationNew = UIInterfaceOrientationPortraitUpsideDown;
}
else {
// Consider same as last time
return;
}
if (orientationNew == orientationLast)
return;
NSLog(#"Going from %# to %#!", [[self class] orientationToText:orientationLast], [[self class] orientationToText:orientationNew]);
orientationLast = orientationNew;
}
#pragma mark -
You need to define UIInterfaceOrientation orientationLast as a member variable and you're set.
Handling all 6 orientations
Though we don't often care about FaceUp / FaceDown orientations, they're still important.
Taking them into account leads to a much more appropriate sensitivity for orientation changes, while leaving them out can lead to metastability & hysteresis.
Here's how I handled it -
- (void)startMonitoring
{
[self.motionManager startAccelerometerUpdatesToQueue:self.opQueue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
if (error != nil)
{
NSLog(#"Accelerometer error: %#", error);
}
else
{
float const threshold = 40.0;
BOOL (^isNearValue) (float value1, float value2) = ^BOOL(float value1, float value2)
{
return fabsf(value1 - value2) < threshold;
};
BOOL (^isNearValueABS) (float value1, float value2) = ^BOOL(float value1, float value2)
{
return isNearValue(fabsf(value1), fabsf(value2));
};
float yxAtan = (atan2(accelerometerData.acceleration.y, accelerometerData.acceleration.x)) * 180 / M_PI;
float zyAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.y)) * 180 / M_PI;
float zxAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.x)) * 180 / M_PI;
UIDeviceOrientation orientation = self.orientation;
if (isNearValue(-90.0, yxAtan) && isNearValueABS(180.0, zyAtan))
{
orientation = UIDeviceOrientationPortrait;
}
else if (isNearValueABS(180.0, yxAtan) && isNearValueABS(180.0, zxAtan))
{
orientation = UIDeviceOrientationLandscapeLeft;
}
else if (isNearValueABS(0.0, yxAtan) && isNearValueABS(0.0, zxAtan))
{
orientation = UIDeviceOrientationLandscapeRight;
}
else if (isNearValue(90.0, yxAtan) && isNearValueABS(0.0, zyAtan))
{
orientation = UIDeviceOrientationPortraitUpsideDown;
}
else if (isNearValue(-90.0, zyAtan) && isNearValue(-90.0, zxAtan))
{
orientation = UIDeviceOrientationFaceUp;
}
else if (isNearValue(90.0, zyAtan) && isNearValue(90.0, zxAtan))
{
orientation = UIDeviceOrientationFaceDown;
}
if (self.orientation != orientation)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self orientationDidChange:orientation];
});
}
}
}];
}
Additionally, I've added a threshold value of 40.0 (instead of 45.0). This makes changes less sensitive, preventing hysteresis at inflection points.
If you only want to react to changes of the main 4 orientations, just do this
if (UIDeviceOrientationIsPortrait(orientation) || UIDeviceOrientationIsLandscape(orientation))
{
// Do something
}
The UIAccelerometer class continues to function when the device orientation is locked. You'll have to work out your own methods of turning its variables into orientation values, but it shouldn't be especially complicated.
Have a play with Apple's AcceleromoterGraph sample app to see what values the accelerometer outputs in different orientations.
my solution using coremotion,it work even when the device has his orientation locked.
let motionManager: CMMotionManager = CMMotionManager()
on the did load method
motionManager.deviceMotionUpdateInterval = 0.01
if motionManager.accelerometerAvailable{
let queue = NSOperationQueue()
motionManager.startAccelerometerUpdatesToQueue(queue, withHandler:
{data, error in
guard let data = data else{
return
}
let angle = (atan2(data.acceleration.y,data.acceleration.x))*180/M_PI;
print(angle)
if(fabs(angle)<=45){
self.orientation = AVCaptureVideoOrientation.LandscapeLeft
print("landscape left")
}else if((fabs(angle)>45)&&(fabs(angle)<135)){
if(angle>0){
self.orientation = AVCaptureVideoOrientation.PortraitUpsideDown
print("portrait upside Down")
}else{
self.orientation = AVCaptureVideoOrientation.Portrait
print("portrait")
}
}else{
self.orientation = AVCaptureVideoOrientation.LandscapeRight
print("landscape right")
}
}
)
} else {
print("Accelerometer is not available")
}
hope it helps.
Most of the answers are using accelerometer, which is the overall acceleration = user + gravity.
But to get a device orientation, it is more accurate to use the gravity acceleration. Using gravity will prevent the edge case when user moves in a particular direction. To access the gravity, we have to use startDeviceMotionUpdates API instead.
let motionManager = CMMotionManager()
motionManager.startDeviceMotionUpdates(to: OperationQueue()) { (data, error) in
guard let gravity = data?.gravity else { return }
let newDeviceOrientation: UIDeviceOrientation
if abs(gravity.y) < abs(gravity.x) {
newDeviceOrientation = gravity.x > 0 ? .landscapeRight : .landscapeLeft
} else {
newDeviceOrientation = gravity.y > 0 ? .portraitUpsideDown : .portrait
}
}
Here isĀ an example of detect device rotation and return UIDeviceOrientation.
This solution using CoreMotion and works in all cases.
Example
let orientationManager = APOrientationManager()
orientationManager.delegate = self
/// start detect rotation
orientationManager.startMeasuring()
/// get current interface orientation
let orientation = orientationManager.currentInterfaceOrientation()
print(orientation.rawValue)
/// stop detect rotation
orientationManager.stopMeasuring()
orientationManager.delegate = nil
conform delegate
extension ViewController: APOrientationManagerDelegate {
func didChange(deviceOrientation: UIDeviceOrientation) {
/// update UI in main thread
}
}
APOrientationManager.swift
import Foundation
import CoreMotion
import AVFoundation
import UIKit
protocol APOrientationManagerDelegate: class {
func didChange(deviceOrientation: UIDeviceOrientation)
}
class APOrientationManager {
private let motionManager = CMMotionManager()
private let queue = OperationQueue()
private var deviceOrientation: UIDeviceOrientation = .unknown
weak var delegate: APOrientationManagerDelegate?
init() {
motionManager.accelerometerUpdateInterval = 1.0
motionManager.deviceMotionUpdateInterval = 1.0
motionManager.gyroUpdateInterval = 1.0
motionManager.magnetometerUpdateInterval = 1.0
}
func startMeasuring() {
guard motionManager.isDeviceMotionAvailable else {
return
}
motionManager.startAccelerometerUpdates(to: queue) { [weak self] (accelerometerData, error) in
guard let strongSelf = self else {
return
}
guard let accelerometerData = accelerometerData else {
return
}
let acceleration = accelerometerData.acceleration
let xx = -acceleration.x
let yy = acceleration.y
let z = acceleration.z
let angle = atan2(yy, xx)
var deviceOrientation = strongSelf.deviceOrientation
let absoluteZ = fabs(z)
if deviceOrientation == .faceUp || deviceOrientation == .faceDown {
if absoluteZ < 0.845 {
if angle < -2.6 {
deviceOrientation = .landscapeRight
} else if angle > -2.05 && angle < -1.1 {
deviceOrientation = .portrait
} else if angle > -0.48 && angle < 0.48 {
deviceOrientation = .landscapeLeft
} else if angle > 1.08 && angle < 2.08 {
deviceOrientation = .portraitUpsideDown
}
} else if z < 0 {
deviceOrientation = .faceUp
} else if z > 0 {
deviceOrientation = .faceDown
}
} else {
if z > 0.875 {
deviceOrientation = .faceDown
} else if z < -0.875 {
deviceOrientation = .faceUp
} else {
switch deviceOrientation {
case .landscapeLeft:
if angle < -1.07 {
deviceOrientation = .portrait
}
if angle > 1.08 {
deviceOrientation = .portraitUpsideDown
}
case .landscapeRight:
if angle < 0 && angle > -2.05 {
deviceOrientation = .portrait
}
if angle > 0 && angle < 2.05 {
deviceOrientation = .portraitUpsideDown
}
case .portraitUpsideDown:
if angle > 2.66 {
deviceOrientation = .landscapeRight
}
if angle < 0.48 {
deviceOrientation = .landscapeLeft
}
case .portrait:
if angle > -0.47 {
deviceOrientation = .landscapeLeft
}
if angle < -2.64 {
deviceOrientation = .landscapeRight
}
default:
if angle > -0.47 {
deviceOrientation = .landscapeLeft
}
if angle < -2.64 {
deviceOrientation = .landscapeRight
}
}
}
}
if strongSelf.deviceOrientation != deviceOrientation {
strongSelf.deviceOrientation = deviceOrientation
strongSelf.delegate?.didChange(deviceOrientation: deviceOrientation)
}
}
}
func stopMeasuring() {
motionManager.stopAccelerometerUpdates()
}
func currentInterfaceOrientation() -> AVCaptureVideoOrientation {
switch deviceOrientation {
case .portrait:
return .portrait
case .landscapeRight:
return .landscapeLeft
case .landscapeLeft:
return .landscapeRight
case .portraitUpsideDown:
return .portraitUpsideDown
default:
return .portrait
}
}
}
Use of CMMotionManager may help, but not the above way. The above logic is not a stable one. I have tested throughly and found that by seeing the values of acceleration.x/y/z are not helping to determine the orientation.
Instead, I got a way to find the orientation WRT the angle i.e.
float angle = (atan2(accelerometerData.acceleration.y,accelerometerData.acceleration.x))*180/M_PI;
And for orientation,-
if(fabs(angle<=45)currOrientation=UIDeviceOrientationLandscapeRight;
else if((fabs(angle)>45)&&(fabs(angle)<135))currOrientation=((angle>0)?UIDeviceOrientationPortraitUpsideDown:UIDeviceOrientationPortrait);
else currOrientation = UIDeviceOrientationLandscapeLeft;
This might come handy for someone, though this doesn't help me to find 2 other orientations i.e. UIDeviceOrientationFaceUp & UIDeviceOrientationFaceDown.
Using Satachito's great answer here is code which will also detect if the device is face up or face down
import CoreMotion
var mm: CMMotionManager!
init() {
self.mm = CMMotionManager()
self.mm.accelerometerUpdateInterval = 0.2
}
public func startOrientationUpdates() {
// Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
// Dispatch U/I code to main thread using dispach_async in the handler.
self.mm.startAccelerometerUpdates( to: OperationQueue() ) { p, _ in
if let p = p {
if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z < -0.95) {
print("face up")
}
else if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z > 0.95) {
print("face down")
}
else {
print(
abs( p.acceleration.y ) < abs( p.acceleration.x )
? p.acceleration.x > 0 ? "Right" : "Left"
: p.acceleration.y > 0 ? "Down" : "Up"
)
}
}
}
}
public func endOrientationUpdates() {
self.mm.stopAccelerometerUpdates()
}