본문 바로가기

프로그래밍/iOS

[ios]화면 기울기에 따라 스크롤 하기(가속도계 이용)

이번 예제는 패드 혹은 폰을 기울임에 따라 화면 스크롤을 해주는 예제

 

계속 예제를 올리는데 이는 Cookbook예제이고,

 

이 예제 버전이  옛 버전이기 때문에 ios7에 맞게 함수들을 바꾸어 기술함.



먼저 가속도계를 사용하기 위해  CoreMotion프레임 웍을 추가

 

ViewController.h파일에서

 

 

#import <CoreMotion/CoreMotion.h>와 <UIAccelerometerDelegate>를 추가 후

필요한 변수들을 추가한다.

 

다음으로 viewController.m파일에

스크롤뷰를 사용하기 위해 loadView함수를 추가

 

- (void) loadView

{

    [super loadView];

    //스크롤 넣기

    sv = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    self.view = sv;

}

 

0.03초마다 호출될 tick함수 추가

 

- (void) tick

{

    //현재속도를 각각 x,y offset 더함

    xoff += xvelocity;

     yoff += yvelocity;

    

    //속도를 1.0f~0.0f사이로 맞춤,

    xoff = MIN(xoff, 1.0f);

    xoff = MAX(xoff, 0.0f);

    yoff = MIN(yoff, 1.0f);

    yoff = MAX(yoff, 0.0f);

    

    //현재의 속도에 맞춰 보이는 화면 갱신

    CGFloat xsize = sv.contentSize.width - sv.frame.size.width;

    CGFloat ysize = sv.contentSize.height - sv.frame.size.height;

    sv.contentOffset = CGPointMake(xoff * xsize, yoff * ysize);

 

}

 

화면 세로고정을 위한 shouldAutorotate와 supportedInterfaceOrientation함수 추가

 

-(BOOL)shouldAutorotate

{

    return YES;

}

-(NSUInteger)supportedInterfaceOrientations

{

    return UIInterfaceOrientationMaskPortrait;

 

}

 

이 후 실제 동작을 담당할 viewDidAppear함수 추가

 

-(void)viewDidAppear:(BOOL)animated

{

    NSString *map = @"http://maps.weather.com/images/maps/current/curwx_720x486.jpg";

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    [queue addOperationWithBlock:

     ^{

         // 날씨 데이터 가져옴

         NSURL *weatherURL = [NSURL URLWithString:map];

         NSData *imageData = [NSData dataWithContentsOfURL:weatherURL];

         

         // 메인 큐를 이용해 메인 스레드의 이미지 갱신

         [[NSOperationQueue mainQueue] addOperationWithBlock:^{

             UIImage *weatherImage = [UIImage imageWithData:imageData];

             UIImageView *imageView = [[UIImageView alloc] initWithImage:weatherImage];

             CGSize initSize = weatherImage.size;

             CGSize destSize = weatherImage.size;

             //콘텐트 크기를  번에 보이는 화면보다 크게 설정

             while ((destSize.width < (self.view.frame.size.width * 4)) ||

                    (destSize.height < (self.view.frame.size.height * 4)))

             {

                 destSize.width += initSize.width;

                 destSize.height += initSize.height;

             }

             

             imageView.userInteractionEnabled = NO;

             imageView.frame = (CGRect){.size = destSize};

             sv.contentSize = destSize;

             

             [sv addSubview:imageView];

             //가속도계 실행

             motionManager=[[CMMotionManager alloc]init];

             NSOperationQueue *queue=[[NSOperationQueue alloc]init];

             if(motionManager.accelerometerAvailable)

             {

                 motionManager.accelerometerUpdateInterval=1.0/10.0;

                 [motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData* accelerometer, NSError* error){

                     if(error)

                     {

                         [motionManager stopAccelerometerUpdates];

                     }

                     else

                     {

                         // 가속도계  추출

                         float xx =-accelerometer.acceleration.x;

                         float yy = (accelerometer.acceleration.z + 0.5f) * 2.0f; // between face up and face forward

                         

                         // 가속도 방향변화 확인

                         float accelDirX = SIGN(xvelocity) * -1.0f;

                         float newDirX = SIGN(xx);

                         float accelDirY = SIGN(yvelocity) * -1.0f;

                         float newDirY = SIGN(yy);

                         

                         //객체 가속

                         if (accelDirX == newDirX) xaccel = (abs(xaccel) + 0.005f) * SIGN(xaccel);

                         if (accelDirY == newDirY) yaccel = (abs(yaccel) + 0.005f) * SIGN(yaccel);

                         

                         // 현재 속도에 가속도계의 변화 반영

                         xvelocity = -xaccel * xx;

                         yvelocity = -yaccel * yy;

                     }

                 }

                  ];

             }

             else//가속도계사용불가

             {

                 UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"경고" message:@"현재기기에서는 가속도계측이 불가합니다." delegate:self cancelButtonTitle:@"확인" otherButtonTitles:@"취소",nil];

                 [alert show]; //경고창 출력

             }

             // 물리 타이머 시작

             [NSTimer scheduledTimerWithTimeInterval: 0.03f target: self selector: @selector(tick) userInfo: nil repeats: YES];

         }];

     }];

 

 

}

 

SIGN을 알지 못하므로 #define문 추가

 

 #define SIGN(_NUM_) ((_NUM_ < 0) ? (-1) : 1)

 

마지막으로 appdelegate.m파일로 가서

필요한 ViewController파일, window변수, 뷰컨트롤러 설정을 하면 된다.

 

이 후 실행을 하면

 

위에서 볼 수 있는 지도를 화면 기울기에 따라서 움직일 수 있다.

 

실제로 구동하면 아래화면과 같이 지도의 일부가 나오며 기기를 기울임에 따라 움직이는 모습을 확인할 수 있다.

 

화살표는 동작의 이해를 돕기위해 추가한 것이며 실제 앱상에서는 등장하지 않습니다.

대각선으로 기울여도 동작합니다.