I get a number of artifacts and incorrect behavior when trying to switch views in a ViewFlipper. I want to add and remove views on demand, so, instead of using XML, I must call ViewGroup.addView(). At certain times I want to clean up the container by removing all children but the last. Here is a demo:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
final ViewFlipper flipper = new ViewFlipper(this);
Animation in = new TranslateAnimation(-200, 0, 0, 0);
in.setDuration(300);
Animation out = new TranslateAnimation(0, 200, 0, 0);
out.setDuration(300);
flipper.setInAnimation(in);
flipper.setOutAnimation(out);
// clean it up
out.setAnimationListener(new AnimationListener(){
@Override
public void onAnimationEnd(Animation animation) {
flipper.post(new Runnable(){
public void run() {
flipper.removeViews(0, flipper.getChildCount() - 1);
}
});
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationStart(Animation animation) {}
});
Button button = new Button(this);
button.setText("Click me");
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
View a = makeView();
flipper.addView(a);
flipper.showNext();
}
});
root.addView(button);
root.addView(flipper);
setContentView(root);
}
int i = 0;
public View makeView() {
TextView tv = new TextView(MainActivity.this);
tv.setText("TextView#" + i++);
tv.setTextSize(30);
return tv;
}
}
Sometimes I want to remove all children but the last added, to save memory and because those children will never be used again (Maybe I can recycle them, but that’s another story). I use a simple runnable scheduled via View.post() in the animation listener, and exactly once every three times there are artifacts.
Using View.post(Runnable) is required because if you remove children directly in the animation listener, NullPointerException are thrown because (at least on Honeycomb+, which uses display lists to draw hierarchies).
Note: I’m developing for 2.1+, so the Honeycomb animation packages doesn’t suit.
Those “artifacts” appear because in your case you try to remove all the views except the one at the top leaving the index of the current displayed child out of order. The
ViewFlipperwill try to compensate this and from the looks of it doesn’t succeed. But you could still do what you want with no visual problems like this:This should leave only the visible View in the
ViewFlipper. See if the code solves the problem.