Skip to content

5. 이벤트

JaeWoong Oh edited this page Jun 19, 2017 · 110 revisions

Event

Interaction을 개발하다 보면 필요한 타이밍에 UI변경 및 사용자 입력에 대한 처리를 해야합니다. Propose는 애니메이션 및 모션 사이클에 대한 각종 Event를 제공합니다.

Event는 Animation, Motion, Propose 이렇게 3가지 영역으로 나누어지고 각각에 대한 Listener를 구현할수 있습니다.

Animation event

play되는 Animator 하나하나마다 Event를 얻을수 있으며 시작,끝,진행상황에 대한 Event를 정의 할수 있습니다.

JwAnimatorListener

  • Animation의 시작과 끝 진행상황에 대한 Event를 얻습니다.
  • Propose에선 Reverse Animation을 지원하고 있는데 이에 대해도 Event를 받을수 있습니다.
  • JwAnimatorListener는 Animator.addListener() 등록 할수 있습니다.
animator.addListener(new JwAnimatorListener(){
	public void onStart(Animator animation){
	 //애니메이션이 시작 지점으로 들어 올때마다 호출됨
	}
	public void onEnd(Animator animation){
	 //애니메이션이 종료 지점으로 들어 올때마다 호출됨
	}
	public void onReverseStart(Animator animation){
	 //Reverse 애니메이션이 시작 지점으로 들어 올때마다 호출됨
	}
	public void onReverseEnd(Animator animation){
	 //Reverse 애니메이션이 종료 지점으로 들어 올때마다 호출됨
	}
});

  • 3D flipping 예제
    카드를 뒤집는 효과내는 예제를 구현 해보도록 하죠
    카드의 앞면(front)과 뒷면(back) 두개의 회전 애니메이션을 만들고 조합 합니다.
ObjectAnimator front = ObjectAnimator.ofFloat(flip_img, View.ROTATION_Y, 0,90);
front.setDuration(500);  
ObjectAnimator back= ObjectAnimator.ofFloat(flip_img, View.ROTATION_Y, -90,0);
back.setDuration(500);
Propose propose = new Propose(this); 
propose.motionRight.play(front).next(back); /** set right move Animator **/
propose.motionRight.setMotionDistance(200*Propose.getDensity(this)); /** set Drag Distance **/	
flip_img.setOnTouchListener(propose);	  /** set touch listener **/

여기서 0˚-180˚로 회전하는 한개의 애니메이션으로 구성하지 않은 것은 View가 180도 회전하면 이미지가 반대로 뒤집혀 보이기 때문입니다.
애니메이션을 front/back 두개로 나누고 back 애니메이션은 -90˚~0˚로 회전하여 정상적으로 이미지가 보이게 하였습니다.

Result
CardFlip

JwAnimatorListener로 애니메이션이 반전될때의 Event를 얻을수 있습니다. 아래코드를 추가하면 카드가 뒤집힐때 이미지가 변경되는 효과를 줄수 있습니다.

front.addListener(new JwAnimatorListener() {
	public void onStart(Animator arg0) {}
		public void onEnd(Animator arg0) {
		flip_img.setBackgroundResource(R.drawable.girl_background);
		flip_img.setImageResource(R.drawable.girl);
	}
	public void onReverseStart(Animator arg0) {
		flip_img.setBackgroundResource(R.drawable.boy_background);
		flip_img.setImageResource(R.drawable.boy);
	}
		public void onReverseEnd(Animator arg0) {}
	});

Result ( full source code )
3DFlip

AnimatorUpdateListener

  • Property Animation에 제공하는 Listener를 그대로 사용할수 있습니다. Animator가 진행될때 상태값을 체크하기 위해 AnimatorUpdateListener를 사용합니다.
paperAnim.addUpdateListener(new AnimatorUpdateListener() {
	public void onAnimationUpdate(ValueAnimator animation) {
		 //애니메이션이 진행될때 마다 호출됨
		}
	});

Note : 이 밖에 Property animation에서 제공되는 모든 listener를 사용할수 있습니다.


Motion event

Motion은 애니메이션 조합으로 구성되어 있고 전체 애니메이션 사이클에 대한 Event를 받을수 있습니다.

MotionListener

  • Motion의 시작과 끝 진행상황에 대한 Event를 얻습니다.

  • MotionListener은 propose.motionRight.setOnMotionListener()로 등록 할수 있습니다.

propose.motionRight.setOnMotionListener(new MotionListener() {
	public void onStart(boolean isForward) {
		//모션이 시작될때 마다 호출						
	}
	public void onScroll(long currDuration, long totalDuration,	boolean isForward) {
		//모션이 진행될때 마다  호출
	}
	public void onEnd(boolean isForward) {
		//모션이 종료될때 마다 호출
	}
});
  • Alpha view 예제
    View가 sliding될 때 배경이 점점 어두어지는 Interaction을 자주 보게 됩니다.
    위 Card Fling 예제에 아래의 코드를 추가하면 Motion의 움직임에 따라 Alpha값이 변경 되는것을 확인 할수 있습니다.
propose.motionRight.setOnMotionListener(new MotionListener() {
	public void onStart(boolean isForward) {}
		public void onScroll(long currDuration, long totalDuration, boolean isForward) {
		float alpha = (float)currDuration/totalDuration*0.8f;
		findViewById(R.id.back_lyt).setAlpha(alpha); 
	}
		public void onEnd(boolean isForward) {}
});

Result ( full source code )
Alpha

Propose Event

Propose는 방향에 대한 4개의 Motion을 관리하고 있고 전체적인 시작과 끝 그리고 진행 상황에 대한 Event를 얻습니다.

ProposeListener

  • Propose는 전반적으로 Motion의 상태 및 시작과 끝을 관리하고 이에 대한 Event를 받을수 있습니다.

  • ProposeListener는 Propose.setOnProposeListener()로 등록 할수 있습니다.

propose.setOnProposeListener(new ProposeListener() {
	public void onStart() {
      		    //Propose가 시작될때 한번만 호출됨
      		}
	public void onScroll(int Direction, long currDuration, long totalDuration) {
           //Propose에 속한 어떤 motion이든 진행될때마다 호출됨
           // 해당 모션은 Direction으로 구분할수 있음
	}
	public void onEnd() {
            //모든 Motion과 애니메이션이 종료될때 한번만 호출됨
	}
});
  • Lion view 예제
    Motion들을 조합하면 자유롭게 이동하는 사자 View를 구현할수 있습니다.
ObjectAnimator rightMove = ObjectAnimator.ofFloat(moving_lyt, View.TRANSLATION_X, 0,end);
ObjectAnimator rightDown = ObjectAnimator.ofFloat(moving_lyt, View.TRANSLATION_Y, 0,end);
rightMove.setInterpolator(null);
rightDown.setInterpolator(null);
rightMove.setDuration(1000);
rightDown.setDuration(1000);
	
Propose propose = new Propose(this);
propose.motionRight.play(rightMove);
propose.motionRight.setMotionDistance(end).enableTabUp(false); // right move option
propose.motionDown.play(rightDown);
propose.motionDown.setMotionDistance(end).enableSingleTabUp(false).enableFling(false).enableTabUp(false);
propose.motionRight.move(end/2);// center_horizontal lion
propose.motionDown.move(end/2); // center_vertical lion
moving_lyt.setOnTouchListener(propose);

Result ( full source code )
3DFlip

이때 사자가 어느 방향이든(Motion) 움직임이 시작될때 달리는 모습을 표현 한다면 더할나위 없겠죠.
아래는 사자가 이동할때 뛰는 효과를 위해 ProposeListener를 사용하였습니다.

final ObjectAnimator running = ObjectAnimator.ofFloat(lion_img,View.ROTATION, 0,-10,20,40,20);
running.setRepeatCount(ObjectAnimator.INFINITE);
running.setDuration(150);
	
propose.setOnProposeListener(new ProposeListener() {
	public void onStart() { 
		running.start();
	}
	
	public void onScroll(int arg0, long arg1, long arg2) {}
	
	public void onEnd() {
		lion_img.setRotation(0f);
		running.cancel();
	}
});

Result ( full source code )
3DFlip

MotionInitor

Property animation에서 가장 불편했던 점은 사이즈를 명시해야 된다는 것입니다. Android에서는 View가 완전히 loading되기 전에 사이즈를 가져올수 없는데 그것을 해결하기 위해 view.onPost()를 사용 합니다.

Propose에서는 특별히 MotionInitor를 제공합니다. MotionInitor는 View가 touch되는 순간 사이즈를 받아올수 있습니다. View의 크기가 변하더라도 동적으로 사이즈를 받을수 있어 매우 유용합니다.

  • MotionInitor 는 Propose.setOnMotionInitor()로 등록 할수 있습니다.

  • MotionInitor에느 touchDown,touchUp이 있으며 모든 Event중 가장 먼저 호출됩니다.

  • MotionInitor.addParam("key",View)를 사용하여 View를 등록하고 touchDown에서 getParam("key")을 사용해 동적인 정보를 얻어올수 있습니다.

MotionInitor initor = new MotionInitor() {
	public void touchDown(Propose propose) {
		//getParam을 사용하여 해당 View를 리턴받고 사이즈를 얻을수 있다.
		View lion_view = (View)getParam("lion");
		int width = lion_view.getWidth();
		//Animation 혹은 Distance 등의 값을 설정한다.
		propose.motionRight.setMotionDistance(width);
	}
	public void touchUp(Propose propose) {
		//view touchUp 시 필요한 내용을 초기화 할수있다. 
	}
};
// touchDown시 사이즈를 얻어올 View 등록(key값에 대응하여 여러개 등록가능)
initor.addParam("lion", lion_view);
propose.setOnMotionInitor(initor);

.