1

내 앱에서 올바르게 움직일 조각을 가져올 수 있지만 애니메이션과 일치하지 않는 무언가가 있습니다.FragmentTransaction 애니메이션이 작동하지만 이상하게 보입니다.

구체적으로 말하면 : 저는 2 프레임과 3 조각의 활동이 있습니다. 두 개는 고정되어 있고 세 번째는 왼쪽에서 오른쪽으로 움직여서 첫 번째를 덮고 숨 깁니다.

모바일 조각이 이동하면 시작 지점에서 끝 지점까지 이동하기 전에 최종 위치에 순간적으로 나타납니다 (애니메이션 리소스 slide_in_left, slide_in_right, slide_out_left 및 slide_out_right).

EDIT : 내 테스트 장치는 2 세대 넥서스 7 및 삼성 갤럭시 s3이므로 하드웨어 문제가 아니어야합니다. 에뮬레이터가 너무 많은 프레임을 건너 뜁니다.

3 개의 모든 조각을 함께 이동하면이 문제가 발생하지 않습니다.

이 문제를 설명하기 위해 간단한 응용 프로그램을 만들었습니다. 아마도 누군가 해결책을 발견 할 수 있습니다. 다음은 관련 파일은 다음과 같습니다

MainActivity.java

public class MainActivity extends Activity { 

    MainFragment mFragment1; 
    MainFragment mFragment2; 
    MainFragment mFragment3; 
    // variable to hold current frame for mFragment2 
    int mFrag2Frame; 



    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     if (savedInstanceState != null) { 
      mFrag2Frame = savedInstanceState.getInt("frag_2_frame"); 
     } else { 
      mFrag2Frame = R.id.rightFrame; 
     } 
     // First add mFragment1 and mFragment3 where they will stay. 
     // Then add mFragment2 over the top of its current frame 
     FragmentTransaction ft = getFragmentManager().beginTransaction(); 
     ft.add(R.id.leftFrame, mFragment1 = MainFragment.Frag1()) 
       .add(R.id.rightFrame, mFragment3 = MainFragment.Frag3()) 
       .add(mFrag2Frame, mFragment2 = MainFragment.Frag2()) 
       .commit(); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 

     outState.putInt("frag_2_frame", mFrag2Frame); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 

     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 

     int id = item.getItemId(); 
     if (id == R.id.action_slide) { 
      slide(); 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    public void slide() { 

     boolean isLeft = mFrag2Frame == R.id.leftFrame; 
     FragmentTransaction ft = getFragmentManager().beginTransaction(); 

     // set animations according to current position of mFragment2 
     ft.setCustomAnimations(isLeft ? R.anim.slide_in_left : R.anim.slide_in_right, 
       isLeft ? R.anim.slide_out_right : R.anim.slide_out_left); 

     // change mFrag2Frame according to its current value 
     mFrag2Frame = isLeft ? R.id.rightFrame : R.id.leftFrame; 

     ft.remove(mFragment2) 
       .add(mFrag2Frame, mFragment2 = MainFragment.Frag2()) 
       .commit(); 
    } 
} 

main.xml에

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/LinearLayout1" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context="com.example.slidingpanels.MainActivity" > 

    <FrameLayout 
     android:id="@+id/leftFrame" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" > 

    </FrameLayout> 

    <FrameLayout 
     android:id="@+id/rightFrame" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" > 

    </FrameLayout> 

</LinearLayout> 

MainFragment.java

public class MainFragment extends Fragment { 

    int mResourceId = R.layout.frag; 
    int mColour; 

    public MainFragment() { 
    } 

    private MainFragment(int colour) { 
     mColour = colour; 
    } 

    public static MainFragment Frag1() { 
     return new MainFragment(Color.RED); 
    } 
    public static MainFragment Frag2() { 
     return new MainFragment(Color.GREEN); 
    } 
    public static MainFragment Frag3() { 
     return new MainFragment(Color.BLUE); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 

     View view = inflater.inflate(mResourceId, container, false); 
     view.setBackgroundColor(mColour); 
     return view; 
    } 
} 

frag.xml

<?xml version="1.0" encoding="utf-8"?> 
<com.example.slidingpanels.SlidingImageView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/SlidingImageView1" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:src="@drawable/ic_launcher" > 

</com.example.slidingpanels.SlidingImageView> 
,536,913 63,210

SlidingImageView.java

public class SlidingImageView extends ImageView { 

    public SlidingImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     // TODO Auto-generated constructor stub 
    } 

    public float getXFraction() { 

     int width = this.getWidth(); 
     return (width == 0) ? 0 : getX()/(float) width; 
    } 

    public void setXFraction(float xFraction) { 

     int width = this.getWidth(); 
     setX((width > 0) ? (xFraction * width) : 0); 
    } 
} 

그리고 마지막으로, 나는 정확히 같은 문제를 했어

<?xml version="1.0" encoding="utf-8"?> 
<set> 
    <objectAnimator 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:propertyName="xFraction" 
     android:valueType="floatType" 
     android:valueFrom="-1" 
     android:valueTo="0" 
     android:duration="500" /> 
</set> 

답변

2

내 slide_in_left.xml을 ... 포함됩니다

플리커/결함 onMeasure가 발생하기 전에 setXFraction이 처음 호출 될 때 getWidth()가 0을 반환하면 조각이 스크롤되지 않은 위치에있는 첫 번째 그려진 프레임을 의미하므로 다음 호출은 onMeasure와 올바른 위치에 그려집니다getWidth가 현재 유효한 데이터를 반환하고 있기 때문입니다.

내가 찾은 해결책은 뷰 객체의 X 부분을 float로 저장 한 다음 onMeasure()를 재정 의하여 mXfract * measureSpec을 사용하여 setTranslationX를 다시 수행하는 것입니다. 나를 위해

작품은, 아래의 코드는 :

public class SlidingFrameLayout extends FrameLayout { 

    private static final String TAG = SlidingFrameLayout.class.getSimpleName(); 

    private float mXfract=0f; 
    private float mYfract=0f; 

    public SlidingFrameLayout(Context context) { 
     super(context); 
    } 

    public SlidingFrameLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public SlidingFrameLayout(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    public void setYFraction(final float fraction) { 
     mYfract=fraction; 
     float translationY = getHeight() * fraction; 
     setTranslationY(translationY); 
    } 

    public float getYFraction() { 
     return mYfract; 
    } 

    public void setXFraction(final float fraction) { 
     mXfract=fraction; 
     float translationX = getWidth() * fraction; 
     setTranslationX(translationX); 
    } 

    public float getXFraction() { 
     return mXfract; 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     int width = MeasureSpec.getSize(widthMeasureSpec); 
     int height = MeasureSpec.getSize(heightMeasureSpec); 
     // Correct any translations set before the measure was set 
     setTranslationX(mXfract*width); 
     setTranslationY(mYfract*height); 
    } 
} 

편집 : 너비/높이 대신 호출 measurespec 사용합니다.

+0

굉장 !! 그건 완벽하게 작동하지만 setTranslationX()와는 반대로 setX()를 계속 사용했습니다. javadoc은 setTranslationX()가이 목적에 더 적합 할 수 있다고 제안합니다 ... 당신의 생각은 무엇입니까? –

+0

그들은 꽤 다르지만 레이아웃에 따라 똑같이 보일 수 있습니다.보기가 왼쪽 상단 0,0에 있으면 부모에서 오프셋이 매우 다르면 매우 똑같을 것입니다 : setX/Y - 부모 0 내의 위치 설정 , 0. setTransitionX/Y - 뷰의 기본 위치에 대한 상대 위치를 설정합니다. – Cakey

관련 문제