2013-04-08 3 views
9

Fragments에 대해 Animation을 만들었습니다. 은 탭 사이에서 움직이는 애니메이션입니다. 그 이유는 현재 Fragment에 애니메이션을 적용하여 화면에서 완전히 벗어나야하고, 반대쪽에서 Fragment 슬라이드가 필요합니다. 같은 종류의 AnimationViewPager을 사용합니다.XML에서 화면 크기의 특정 애니메이션을 정의하는 방법

View의 절대 시작 및 끝 위치를 지정해야하며 다른 장치의 치수가 다르기 때문에 Animation을 모든 장치에 맞는 것으로 정의 할 수 없습니다. 더 큰 장치에서는 View이 화면을 완전히 슬라이드하지 않을 수 있으며 더 작은 장치에서는 View이 많이 움직이고 화면에서 벗어 났을 때 계속 움직입니다.

내 질문에 짐작할 수 있습니다. Fragment을 모든 장치에 동시에 맞출 수있는 XML 애니메이션을 어떻게 정의 할 수 있습니까?

내 애니메이션 :

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android">  

    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/linear_interpolator" 
    android:propertyName="x" 
    android:valueType="floatType" 
    android:valueTo="720" 
    android:valueFrom="0" 
    android:duration="300"/> 

</set> 

답변

17

1) : 당신이 ObjectAnimator를 사용하려면

Existing answers on SO는 FrameLayout이 서브 클래 싱 제안 ...

당신은이 View 애니메이션을 적용 할 서브 클래 싱 할 수 밖에 없다 . 기본적으로 getter 및 setter 메서드를 호출하여 Animation을 수행하므로 마법을 수행하는 데 필요한 getter 및 setter 메서드를 ObjectAnimator에 제공해야합니다.

당신이 ( Animate the transition between fragments)에 연결되는 질문 setXFraction()getXFraction() 방법을 추가 FrameLayout의 서브 클래스입니다

. 이것들은 FrameLayout의 너비를 기준으로 x 값을 설정하는 방식으로 구현됩니다. 이렇게하면 ObjectAnimator은 절대 값 사이에서 애니메이션을 만드는 것 외에 다른 작업을 수행 할 수 있습니다.

요약하면 ObjectAnimator 자체는 실제로 많은 애니메이션을 적용하지 않으며 리플렉션을 통해 getter 및 setter 메서드를 호출합니다.

XML 파일에 실제 화면 픽셀 치수 ( 이 아님)를 실제로 얻을 수있는 방법이 있습니까?

ObjectAnimator으로는이를 달성 할 방법이 없습니다. ObjectAnimators은 시작 값에서 끝 값으로 보간 만합니다. 위에서 설명한 것처럼 setter 메서드는 실제로 발생하는 것을 정의합니다.폭은 코드 세트를 갖는 미세, 또는 코드를 설정할 수있는 상수를 정의하는 것이다 반환 정의 함수를 호출 예

후 로부터 그 일정한 액세스 화면 폭을 동일하게 상수 상기 xml도 똑같이 유용 할 것입니다.

xml 리소스에 코드 값을 삽입 할 수 없습니다. 빌드 할 때 xml 파일에 포함 된 모든 내용이 APK로 컴파일되며 을 런타임에 변경할 수 없습니다. 그리고 그것은 다른 질문에 대한 답이기도합니다 : 현재 화면 크기를 포함하고있는 xml에서 접근 할 수있는 자원이나 상수 나 아무 것도 없습니다. 앱이 설치된 기기의 화면 크기와 같은 동적 인 값은 앱을 빌드 할 때 앱에 포함 된 모든 정보가 앱에 통합되어 있기 때문에 앱의 일부가 될 수 없습니다.


2) 해결 방법 :보기 애니메이션

한 가지 가능한 솔루션은 ObjectAnimator 대신보기 애니메이션을 사용하는 것입니다. 보기 애니메이션을 사용하면 대신 절대 값의 분수를 지정할 수 있습니다 :이 화면 높이의 0%-100%에서 View 애니메이션 것

<set xmlns:android="http://schemas.android.com/apk/res/android"> 
    <translate android:fromYDelta="-100%" android:toYDelta="0%" android:duration="1000"/> 
</set> 

. 다시 말해 화면이 완전히 끝나고 View의 위치까지입니다. 다음과 같이 사용할 수 있습니다.

Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down); 
view.startAnimation(animation); 

나는 이것이 어떤 도움이되지 않을 수도 있음을 알고 있습니다. ObjectAnimators을 사용해야하고보기 애니메이션을 사용할 수없는 경우가 있습니다. 그러나보기 애니메이션을 사용할 수 있다면이 방법으로 문제를 해결할 수 있습니다.


3 Related question Link to documentation
    • ) 모범 사례
  • 우리가 정말 여기에서 해결해야하는 것은 내가 생각하는 것은 당신의 부분에 오해입니다. 이미 XML에서 정의한 모든 애니메이션에는 절대 시작 및 종료 값이 있습니다. 이러한 값은 정적이며 앱을 컴파일 한 후에는 변경할 수 없습니다.

    리소스가 많은 선택기 및 dp, sp ...와 함께 작동하는 방식을 살펴보면 한 가지 작업을 수행하도록 설계되었음을 알 수 있습니다.
    예를 들어 움직이는 애니메이션을 정의 할 수 있습니다 View by 100dp. Dp는 물리적 크기의 측정 값이며, 100dp는 픽셀 밀도가있는 화면의 실제 크기와 완전히 동일합니다. 셀렉터를 통해 화면의 크기가 작거나 큰 기기에서이 애니메이션을 변경할 수 있습니다. 애니메이션에서 View을 너무 많이 또는 너무 적게 움직일 수 있습니다. 그러나 정적 값만 채울 수 있습니다. 선택기로 작업하는 것 외에도 각 장치의 애니메이션을 사용자 정의 할 수 없습니다.

    리소스가 정적이고 변함없는 것을 위해 설계되었습니다. 치수 또는 문자열 변환에 적합하지만 때로는 애니메이션을 사용하면 약간의 고통이 될 수 있습니다.위에서 말했듯이 뷰 애니메이션은 절대 값 대신 분수를 지정하는 옵션을 제공하여 정적 인 특성을 해결할 수있는 방법을 제공합니다. 하지만 일반적으로 xml에서는 동적 인 것을 정의 할 수 없습니다.

    :

    애니메이션에 대한 구글의 우수의 DevBytes 비디오에서이 인수 모양을 확증 학습과려면 0

    그러면 이러한 예제에서 하나의 애니메이션이 xml에 정의 된 적이 없음을 알 수 있습니다. 코드를 설명하고 표시하는 것이 더 쉽기 때문에 xml로 정의하지 않는다고 주장 할 수는 있지만, 내 생각에이 점이 다시 한번 한 점을 입증합니다.

    정적으로 애니메이션을 정의 할 수 없습니다 순전히 동적 인 값에 의존하는 리소스

    화면 너비/높이는 장치마다 다르므로 각 장치마다 다른 애니메이션이 필요합니다. 뷰 애니메이션 만이 절대 값 대신 분수를 정의 할 수 있기 때문에 그 방법을 제공합니다. 다른 경우에는 프로그래밍 방식으로 애니메이션을 정의해야합니다. 다행히 그 ObjectAnimators에 어렵지 않다 :

    Animator animator = ObjectAnimator.ofFloat(view, View.X, startValue, endValue); 
    animator.start(); 
    

    이 픽셀의 최종 값으로 처음부터 View의 x 위치를 애니메이션 것입니다.

    Animator animator = ObjectAnimator.ofFloat(view, View.X, -view.getWidth(), 0.0f); 
    animator.start(); 
    

    이 (가) 왼쪽에서 슬라이드로 View 애니메이션 것입니다 : 당신이 원하는 것처럼 당신은 애니메이션을 위해 View의 폭에 전달할 수 있습니다. 화면에서 완전히 시작하여 최종 위치에서 정지합니다. 또한 바로이 작업을 수행 할 수 있습니다 :이 대상 x 값에 현재의 x 위치에서 View 애니메이션 것

    view.animate().x(targetValue); 
    

    .

    하지만 제발 오해하지 마세요. 가능한 한 많이 정의해야합니다 (애니메이션 또는 다른 어떤 것일 수도 있음). 자신의 상황과 같이 필요한 경우가 아니라면 하드 코딩 된 애니메이션이나 다른 값은 가능한 한 많이 피해야합니다.


    4) 요약

    그래서 요약 :

    당신은 당신이 필요로하는 getter와 setter 메소드를 추가하지 않고 당신이 ObjectAnimators 수행 할 작업을 수행 할 수 없습니다
  • View 당신은 애니메이션을 적용 할
      .
    • 가능하면 view animations을 사용하십시오. 그들과 함께 View의 너비 또는 높이의 분수를 기반으로 애니메이션을 정의 할 수 있습니다.
    • 위의 방법으로 문제가 해결되지 않거나 상황에 적합하지 않은 경우 programmatically 애니메이션을 정의하십시오. 어떤 경우에도 작동합니다.

    나는 당신을 도울 수 있으면 더 이상의 질문이 있으시면 언제든지 물어보십시오!

  • +0

    대단한 답변 주셔서 감사합니다. 큰 제한은 FragmentTransaction에 애니메이션을 추가 할 수있는 유일한 방법은 setCustomAnimations (int enter, int exit)를 사용하는 것입니다. 그리고 그 API는 Animator 리소스 ID가 아니라 Animator 리소스 ID를 기대합니다. 코드에서 Animator를 정의하는 것은 아무런 문제가되지 않습니다. 그런데 리소스 ID를 부여 할 수 있습니까? –

    +0

    OK, 문제가 해결되었으므로 Fragment의 onCreateAnimator 메소드에서 코드 애니메이터를 만듭니다. –

    +0

    이제 막 onCreateAnimator()에 대해 이야기하고 싶습니다. 직접 생각해 냈습니다. 내가 도울 수있어서 기뻐! –

    3

    그냥 화면 밀도에 따라 다른 폴더를 만들 수 있습니다.

    애니메이션의 xml이 res라는 상위 폴더에있는 anim 폴더에 있다고 가정 해 보겠습니다.

    그런 다음 res에서도 anim-ldpi, anim-mdpi 등을 만듭니다. 화면 밀도를 나타내는 이러한 각 폴더에 각각의 애니메이션을 넣고 안드로이드가 올바른 것을 선택합니다. 현상금에 관한

    +0

    대답은 무엇입니까? 의견을 말하거나 동의하십시오. – j2emanue

    +0

    'anim-ldpi','anim-mdpi' 등은 화면 크기가 아니라 화면 _density_의 변형입니다. – matiash

    +0

    이 답변은 질문의 요점을 놓치고 있다고 생각합니다. –

    0

    누군가 내 작업 솔루션을 요구하고있었습니다. 여기있어. Mono를 통한 C# 코드입니다. 바라건대 Java 작성자가 그 언어에서 무엇이 있어야 하는지를 이해할 수 있기를 바랍니다.

    public class MyFragment: Fragment { 
    
        public int TransitDuration { 
         get { 
         return 500; 
         } 
        } 
    
        public override Animator OnCreateAnimator(FragmentTransit transit, bool enter, int nextAnim) { 
         switch (transit) { 
         case FragmentTransit.FragmentOpen: 
          { 
          if (enter) { 
           return this.EnterFromLeftAnimator; 
          } else { 
           return this.ExitToRightAnimator; 
          } 
          } 
         case FragmentTransit.FragmentClose: 
          { 
          if (enter) { 
           return this.EnterFromRightAnimator; 
          } else { 
           return this.ExitToLeftAnimator; 
          } 
          } 
         default: 
          Animator r = base.OnCreateAnimator(transit, enter, nextAnim); 
          if (r == null) { 
          if (!this.IsAdded) { 
           this.OnContextHidden(); 
          } 
          } 
          return r; 
         } 
        } 
    
    
        public Animator EnterFromLeftAnimator { 
         get { 
         float width = Screen.MainScreen.PixelSize.Width; // this is an object of mine; other code cached the width there long ago. It would actually be better to use the window width. 
         ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", width, 0); 
         animator.SetDuration(this.TransitDuration); 
         Animator r = animator as Animator; 
         return r; 
         } 
        } 
        public Animator ExitToRightAnimator { 
         get { 
         float width = Screen.MainScreen.PixelSize.Width; 
         ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", 0, -width); 
         animator.SetDuration(this.TransitDuration); 
         Animator r = animator as Animator; 
         r.AddListener(new AnimatorEndListenerAdapter(() => this.OnContextHidden())); 
         return r; 
         } 
        } 
        public Animator EnterFromRightAnimator { 
         get { 
         float width = this.ScreenWidth; 
         ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", -width, 0); 
         animator.SetDuration(this.TransitDuration); 
         Animator r = animator as Animator; 
         return r; 
         } 
        } 
        public Animator ExitToLeftAnimator { 
         get { 
         float width = this.ScreenWidth; 
         ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", 0, width); 
         animator.SetDuration(this.TransitDuration); 
         Animator r = animator as Animator; 
         r.AddListener(new AnimatorEndListenerAdapter(() => this.OnContextHidden())); 
    
         return r; 
         } 
        } 
    
        public override void OnActivityCreated(Bundle savedInstanceState) { 
         base.OnActivityCreated(savedInstanceState); 
         this.RetainInstance = true; 
        } 
    
    } 
    
    관련 문제