adsense4


[iPhone][MonoTouch] 9번째 예제 : SnowFall iPhone

어플리케이션 화면에 눈이 내리는 효과를 만들어 보겠습니다. UIView클래스는 애니메이션 처리를 위한 메소드를 제공합니다. 메소드에서 애니메이션에 필요한 작업을 지정해 주면 자동으로 효과를 구현해 주는 아주 편리합니다.

눈이 이동하는 효과가 필요하므로 이번 예제에서도 NSTimer를 사용하겠습니다. 눈 이미지가 화면에서 보이지 않게 되었을 때 메모리에서 제거 하는 함수를 호출하기 위한 Selector의 사용에 대해서 알 수 있습니다.

SnowFall이름으로 새 솔루션을 새성하는 것으로 시작합니다. 솔루션의 프로젝트는 "Window-based" 입니다.
생성된 기본 파일 목록입니다.
눈 이미지를 프로젝트에 추가 하겠습니다.  프로젝트의 팝업 메뉴에서 Add - Add Files를 선택합니다.
파일을 선택하는 윈도우에서 "flake.png"를 선택하여 추가합니다.
추가한 이미지가 컴파일 시에 어플리케이션과 함께 존재 할 수 있도록 "Build Action"을 변경합니다.
"Build Action"은 "Content"로 설정 해야만 컴파일 시에 복사 되는 것을 잊지 말아 주세요.
어플리케이션 아이콘을 등록하겠습니다. 프로젝트의 Options - iPhone Application 화면에서 화면과 같이 지정해 주면 됩니다. 아이콘 이미지는 "flake.png"입니다.

애니메이션을 표현하기 위한 뷰 컨트롤러를 추가 해 보겠습니다. 프로젝트의 팝업 메뉴에서 Add - New Files를 선택합니다.
"New File"윈도우에서 "iPhone"카테고리의 "View Interface Definition with Controller"를 선택합니다. 이것은 xib파일과 관련 컨트롤러 래퍼 클래스를 생성해 주는 타입입니다.
이름은 "SnowFallViewController"를 지정하고 "New"를 눌러 생성합니다.
생성된 파일 목록은 화면과 같습니다. SnowFallViewController.xib에 대해 SnowFallViewController.xib.designer.cs와 SnowFallViewController.xib.cs파일이 생성되었습니다. "*.designer.cs"는 Action이나 Outlet등의 정의가 자동으로 생성되는 xib래퍼 파일입니다. "*.xib.cs"는 컨트롤러에 대한 처리를 담당하는 파일입니다.
추가한 뷰에 대해서 화면 작업은 특별히 없습니다. 간단히 배경색만 아래처럼 지정해 주는 것으로 끝내겠습니다.
추가한 SnowFallViewController를 MainWindow에 등록하여 실행시키면 자동으로 생성이 되도록 해 보겠습니다. "MainWindow.xib"파일을 인터페이스빌더로 수정하겠습니다. Library윈도우에서 "View Controller"객체를 선택합니다.
선택한 "View Controller"객체를 MainWindow.xib의 Window객체 아래에 끌어다 위치 시킵니다.
화면과 같이 "View Controller"가 추가 됩니다.
추가된 뷰 컨트롤러의 디자인 화면입니다. 컨트롤러에 뷰가 추가 될 것임을 표시하고 있습니다. 이번 예제에서는 추가 하지 않습니다.
추가한 "View Controller"의 타입이 UIViewController로 되어 있는 것을 앞에서 추가한 "SnowFallViewController"로 변경합니다. 방법은 "View Controller"의 Identity윈도우에서 Class Identity를 변경해 주면 됩니다.
변경한 후의 화면입니다.
다음은 추가한 뷰컨트롤러를 App Delegate에서 참조할 수 있도록 Outlet을 추가합니다. App Delegate의 Identity윈도우에서 다음 화면과 같이 Outlet을 추가합니다. "snowFallViewController" 이름이며 타입은 "SnowFallViewController"입니다.
추가된 Outlet을 Connections윈도우에서 확인 할 수 있습니다.
"snowFallViewController"이름의 Outlet을 "View Controller"와 연결 해 줍니다. 다음 화면과 같이 마우스로 끌어다 놓기로 지정합니다.
연결된 화면입니다.
인터페이스빌더를 저장하고 종료합니다.

추가한 "SnowFallViewController"를 MainWindow의 뷰로서 등록하겠습니다. "Main.cs"파일을 편집기로 열어 코드를 추가합니다.

Main.cs source :
...
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
window.AddSubview(snowFallViewController.View); .... ①

window.MakeKeyAndVisible ();

return true;
}

// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
...
① window.AddSubView(UIView)메소드를 이용하여 추가합니다. window.MakeKeyAndVisible()이전에 해야 하는 것을 잊지 마세요. MonoDevelop의 편집기는 자동완성 기능을 이용해 화면과 같이 후보 요소를 제공해 줍니다.
Outlet으로 정의한 "snowFallViewController"의 View속성을 이용합니다. 이로서 실행시 자동으로 xib파일을 읽어 들여 초기화 한 후 window에 뷰로 등록하여 화면에 표시하게 됩니다.

애니메이션은 SnowFallViewController에서 담당하므로 애니메이션 처리를 위한 코드를 SnowFallViewController.xib.cs에 작성하겠습니다.

SnowFallViewController.xib.cs source :
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

//include for RectangleF
using System.Drawing; .... (1)
using MonoTouch.ObjCRuntime; .... (2)

namespace SnowFall
{
public partial class SnowFallViewController : UIViewController
{
UIImage flakeImage; .... (3)
#region Constructors

// The IntPtr and initWithCoder constructors are required for controllers that need
// to be able to be created from a xib rather than from managed code

public SnowFallViewController (IntPtr handle) : base(handle)
{
Initialize ();
}

[Export("initWithCoder:")]
public SnowFallViewController (NSCoder coder) : base(coder)
{
Initialize ();
}

public SnowFallViewController () : base("SnowFallViewController", null)
{
Initialize ();
}

void Initialize ()
{
}

#endregion

#region User code
public override void ViewDidLoad () .... (4)
{
base.ViewDidLoad ();

this.View.BackgroundColor = UIColor.FromRGBA(0.5f,0.5f,1.0f,1.0f); .... (5)

flakeImage = UIImage.FromFile("flake.png"); .... (6)

NSTimer.CreateRepeatingScheduledTimer(TimeSpan.FromMilliseconds(100.0f), onTimer); .... (7)
}

public void onTimer()
{
Console.WriteLine("onTimer");
UIImageView flakeView = new UIImageView(this.flakeImage); .... (8)

Random rand = new Random(); .... (9)
int startX = rand.Next(320) % 320; //Math.Round(rand.Next() % 320); .... (10)
int endX = rand.Next(320) % 320; //Math.Round(rand.Next() % 320);
double scale = 1 / Math.Round(rand.NextDouble() % 100) + 1.0; .... (11)
double speed = 1 / Math.Round(rand.NextDouble() % 100) + 1.0;

flakeView.Frame = new RectangleF((float)startX, -100.0f, (10.0f)*(float)scale, (10.0f)*(float)scale); .... (12)
flakeView.Alpha = 0.25f; .... (13)

this.View.AddSubview(flakeView); .... (14)

// important ---------------- flakeView.Handle
UIView.BeginAnimations(null, flakeView.Handle); .... (15)
UIView.SetAnimationDuration(5*speed); .... (16)

flakeView.Frame = new RectangleF((float)endX, 500.0f, 25.0f*(float)scale, 25.0f*(float)scale); .... (17)

UIView.SetAnimationDidStopSelector(new Selector("onAnimationComplete:finished:context:")); .... (18)
UIView.SetAnimationDelegate(this); .... (19)
UIView.CommitAnimations(); .... (20)
}

[Export ("onAnimationComplete:finished:context:")] .... (21)
public void AnimationComplete(NSString animationID, NSNumber finished, UIImageView context) .... (22)
{ // ------------------------------------------------------------------UIImageView context--<- important
Console.WriteLine("onAnimationComplete");

context.RemoveFromSuperview(); .... (23)

context.Dispose(); .... (24)

Console.WriteLine("onAnimationComplete ---- delete flakeView");
}

public override void DidReceiveMemoryWarning ()
{
Console.WriteLine("DidReceiveMemoryWarning");
base.DidReceiveMemoryWarning ();
}

#endregion
}
}
(1) System.Drawing 라이브러리는 그래픽에 필요한 구조체 등을 정의하고 있습니다. 눈 이미지의 좌표등을 계산하기 위해 필요한 RectangleF 구조체를 위해 지정합니다.

(2) MonoTouch.ObjCRuntime은 Objective-C의 Selector를 사용하기 위해 필요합니다.

(3) 눈 이미지를 클래스에서 관리하기 위해 UIImage형으로 멤버 변수를 정의 합니다. 
멤버 변수의 이름은 "flakeImage"입니다.

(4) 뷰컨트롤러가 완전히 로드 된 후에 필요한 처리를 하기 위해 ViewDidLoad()를 재정의 합니다. 편집기에서 "override"를 입력하면 재정의 가능한 이벤트 함수 목록이 화면처럼 나옵니다.

(5) 뷰의 배경색을 변경합니다. this.View.BackgroundColor속성을 UIColor값으로 지정함으로서 변경이 가능합니다.
파라미터로 RGB값을 지정하며 마지막에 alpha값을 줍니다.

(6) "flake.png"파일로부터 UIImage객체를 생성합니다. 생성된 객체는 멤버 변수 flakeImage에 저장합니다.

(7) 주기적인 반복 처리를 위해 타이머를 설정합니다. 미리미터초 단위로 반복을 지정하기 위해 TimeSpan.FromMilliseconds(미리미터초)를 사용합니다. 두번째 파라미터 onTimer함수를 반복적으로 호출합니다.
NSTimer.CreateRepeatingScheduledTimer(TimeSpan.FromMilliseconds(100.0f), onTimer);

(8) flakeImage를 갖는 UIImageView를 생성합니다. 생성된 이미지뷰는 메인뷰에 서브뷰로서 추가되고 움직임을 갖게 됩니다.

(9) 임의의 수를 얻기 위해 Random객체를 생성합니다.

(10) Random.Next(maxValue)메소드는 파라미터의 지정된 값보다 작은 수에서 임의의 정수를 반환해 줍니다.

(11) Random의 또다른 메소드인 Random.NextDouble()은 0.0~1.0사이의 임의의 실수를 반환합니다.
정수와 실수, 필요에 따라 맞는 메소드를 사용하는 것을 기억해 두세요.

(12) (8)에서 생성한 이미지뷰의 시작위치와 크기를 지정합니다. 시작 위치는 x좌표는와 크기는 Random에 의해 다양하게 지정되고, y좌표는 화면에서 -100.0f에서 시작하도록 되어 있습니다.
RectangleF클래스는 2가지 생성자가 있는데 화면에 보이는 생성자를 사용했습니다.

(13) 이미지뷰 flakeView의 alpha값을 0.25f로 지정해 줍니다.

(14) 이미지 뷰를 서브뷰로서 추가합니다. 가장 나중에 추가한 뷰가 화면상에 제일 위에 표시되게 됩니다.

(15) UIView에서 제공하는 애니메이션 블럭의 시작을 지정하는 메소드 UIView.BeginAnimations()입니다. UIView.CommitAnimations()를 만날때까지의 코드를 이용하여 애니메이션을 수행하게 됩니다.
2가지의 생성자중에 화면에 보이는 생성자의 2번째 파라미터에 주의 합니다. 애니메이션 처리 중에 델리게이션등으로 이벤트 처리를 하는 경우 넘겨줄 대상 객체의 포인터 입니다. System.IntPtr형의 포인터가 필요합니다. UIView류의 객체는 IntPtr형의 포인터를 표현하기 위해 Handle속성을 갖고 있습니다. Handle속성을 사용하면 대상 객체의 포인터 정보를 전달 할 수 있습니다.
첫번째 문자열 파라미터는 애니메이션 식별자인데 하나밖에 없는 경우 보통 null을 지정해 줍니다.

(16) 애니메이션이 몇초간 진행되는지 지정합니다. 코드는 이미지뷰당 최소 5초이상 애니메이션이 실행 되도록 지정했습니다.
duration파라미터는 double값이므로 초를 지정할 때 실수를 사용하는 것에 주의하세요.

(17) 이미지뷰가 최종적으로 위치하게 될 곳을 지정하는 코드입니다. y좌표는 500.0f이므로 아이폰 화면의 밖입니다. x좌표와 크기는 Random에 의해 다양하게 바뀝니다. 애니메이션은 (12)에서 지정한 시작위치에서 이곳에서 지정한 마지막 위치로 (16)에서 지정한 시간동안 이동하게 되는 것입니다.

(18) Selector는 지정된 문자열로 지정된 메소드를 호출하기 위해 설정하는 객체입니다. 여기서 지정된 문자열을 갖는 함수를 찾아 실행하게 되는 것입니다. 함수 정의는 (21)처럼 [Export] 지시자를 이용하게 됩니다.
(19) (18)에서 정의한 Selector가 정의된 델리케이트 객체를 지정합니다.
(20) 이 함수를 호출하여 애니메이션 블럭의 코드를 실행 합니다.
(21) Selector로 지정하기 위한 메시지를 정의 하는 코드입니다. [Export ("onAnimationComplete:finished:context:")] 정의된 문자열을 보면 Objective-C의 함수 호출하는 형식과 같습니다.

(22) (21)에서 정의된 메시지를 처리하는 실제 함수입니다. 첫번째 파라미터는 BeginAnimations의 첫번째 파라미터 문자열입니다. null로 지정했기 때문에 항상 null이 반환 됩니다. 두번째 파라미터는 NSNumber형으로 1이 저장됩니다.
세번째 파라미터는 BeginAnimations에서 정의한 두번째 파라미터 값이 저장됩니다. 코드를 보시면 UIImageView형으로 정의가 되어 있습니다. 내부 코드에서 자동으로 IntPtr형을 실제 정의된 형으로 캐스팅 해서 넘겨줍니다.

(23) 해당 뷰를 부모뷰로부터 제거하는 메소드입니다.

(24) C#의 메모리에서 정리하는 메소드 Dispose()를 호출하여 객체를 소멸 시킵니다.

작성된 어플리케이션을 컴파일 해서 실행시켜 봅니다. 화면은 실행 시킨 결과입니다. 상태바 쪽에서 아래로 눈 모양의 이미지가 내리는 듯 이동하는 모습을 확인 할 수 있습니다.

타이머의 시간을 조정함으로서 눈의 갯수를 조정할 수 있습니다. 테스트 해 보세요.

이번 예제는 여기까지입니다.
샘플 코드 : SnowFall.zip





 

통계 위젯 (화이트)

67
50
400459

160x600스크래퍼

네이버Analysis