I have managed to get the fragments in my app to move correctly as I want them to, however, there is something inconsistent with the animation.
To be more specific: I have an activity with 2 frames, and 3 fragments. Two are stationary, and the third moves from left to right, covering and uncovering the first 2.
When the mobile fragment moves, it appears momentarily in its final location before sliding as it should from start to finish (using animation resources slide_in_left, slide_in_right, slide_out_left and slide_out_right).
EDIT: my test devices are a 2nd gen nexus 7 and a Samsung galaxy s3, so it shouldn't be a hardware issue. The emulator skips too many frames to notice it.
If I move all 3 fragments together this does not occur.
I have made a simple application to demonstrate this issue, perhaps someone can shed some light on a solution. Here are the relevant files:
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>
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);
}
}
and finally, I'll include my slide_in_left.xml
<?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>