保留片段[英] Retaining Fragment

本文是小编为大家收集整理的关于保留片段的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在编写一个将在画布上吸引泡沫的应用程序. 我的布局是一个简单的线层,我将其用作片段持有人. 当我在画布上绘制时,我的片段没有XML布局,因此我以这样的方式将其布局设置为:

public class BubbleFragment extends Fragment {

    Bubble bubble;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        //retain fragment
        setRetainInstance(true);

        //bubble = new Bubble(getActivity()); //THIS WILL CRASH APP, MOVE TO onCreateView instetad
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT,
                100);
        LinearLayout ll = new LinearLayout(getActivity());
        ll.setOrientation(LinearLayout.VERTICAL);

        // instantiate my class that does drawing on Canvas
        bubble = new Bubble(getActivity());
        bubble.setLayoutParams(lp);
        bubble.setBackgroundColor(Color.BLUE);
        ll.addView(bubble);  //if you create bubble in onCreate() this will crash.  Create bubble in onCreateView

        return ll;
    }
}

因此,当我启动应用程序时,我希望气泡在屏幕的中间显示并慢慢移动到底部.由于我在上面使用setRetainInstance(true),因此我希望当我旋转屏幕时,气泡会在旋转前停止的地方继续.但是,它是在其初始位置(屏幕中间)的重新绘制.

我想继续从屏幕方向更改之前的位置进行绘画,而不是从一开始.

这是我的气泡代码:

public class Bubble extends View {

    private static final boolean BUBBLING = true; //thread is running to draw

    private Paint paint;
    private ShapeDrawable bubble;

    // coordiantes, radius etc
    private int x;
    private int y;
    private int dx;
    private int dy;
    private int r;
    private int w = 400;
    private int h = 400;

    //handler to invalidate (force redraw on main GUI thread from this thread)
    private Handler handler = new Handler();

    public Bubble(Context context) {
        super(context);

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        w = size.x;
        h = size.y;

        x = w/2;
        y = h/2;
        r = 60;
        dx = 1;
        dy = 1;

        bubble = new ShapeDrawable(new OvalShape());
        bubble.getPaint().setColor(Color.RED);
        bubble.setBounds(0, 0, r, r);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onSizeChanged  (int w, int h, int oldw, int oldh){
        //set bubble parameters (center, size, etc)

        startAnimation();
    }

    public void startAnimation(){
        new Thread(new Runnable() {
            public void run() {
                while (BUBBLING) {
                    moveBubble();

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {

                    }

                    //update by invalidating on main UI thread
                    handler.post(new Runnable() {
                        public void run() {
                            invalidate();
                        }
                    });
                }
            }
        }).start();
    }


    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        // draws bubble on canvas
        canvas.translate(dx, dy);
        bubble.draw(canvas);
        canvas.restore();
    }

    private void moveBubble(){
        dx += 1;
        dy += 1;
        x = x + dx;
        y = y + dy;
        if (bubble.getPaint().getColor() == Color.YELLOW){
            bubble.getPaint().setColor(Color.RED);
        } else {
            bubble.getPaint().setColor(Color.YELLOW);
        }
    }
}

非常感谢,

推荐答案

如果您真的想保留整个视图,则可以执行像懒惰负载之类的事情:

public class BubbleFragment extends Fragment {
    Bubble bubble;
    LinearLayout parent;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        setRetainInstance(true);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        parent = new LinearLayout(activity);
        if(bubble == null) {
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    100);
            bubble = new Bubble(getActivity());
            bubble.setLayoutParams(lp);
            bubble.setBackgroundColor(Color.BLUE);
        }
        parent.setOrientation(LinearLayout.VERTICAL);
        parent.addView(bubble);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        parent.removeView(bubble);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return parent;
    }
}

其他推荐答案

在您的情况下,您不需要setRetainInstance(true),您只需要将实例变量保存在onsaveinstancestate()中,然后将它们加载到onCreate()中.为您的示例,类似:

public void onCreate(Bundle b) {
    super.onCreate(b);
    if(b != null) {
        xPos = b.getInt("x");
        yPos = b.getInt("y");
    }
}

public void onSaveInstanceState(Bundle b) {
    super.onSaveInstanceState(b);
    b.putInt("x",xPos);
    b.putInt("y",yPos);
}

顺便说一句,您无法在onCreate()中创建泡泡的原因是因为该片段在称为onAtivitive created()之前与其活动完全关联,而该片段被称为onCreate().

.

本文地址:https://www.itbaoku.cn/post/2091078.html

问题描述

I am writing an app that will draw a bubble on Canvas. I have MainActivity with its layout as a simple LinearLayout which I use as holder for fragment. My fragment has no xml layout as I am drawing on Canvas, so I set its layout programmatically like this:

public class BubbleFragment extends Fragment {

    Bubble bubble;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        //retain fragment
        setRetainInstance(true);

        //bubble = new Bubble(getActivity()); //THIS WILL CRASH APP, MOVE TO onCreateView instetad
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT,
                100);
        LinearLayout ll = new LinearLayout(getActivity());
        ll.setOrientation(LinearLayout.VERTICAL);

        // instantiate my class that does drawing on Canvas
        bubble = new Bubble(getActivity());
        bubble.setLayoutParams(lp);
        bubble.setBackgroundColor(Color.BLUE);
        ll.addView(bubble);  //if you create bubble in onCreate() this will crash.  Create bubble in onCreateView

        return ll;
    }
}

So, when I start my app, I am expecting bubble to show in the middle of the screen and move slowly towards bottom. Since I use setRetainInstance(true) above, I am expecting that when I rotate my screen, the bubble will continue where it left off before rotation. However, it is redraws at its initial location (middle of the screen).

I would like to to continue drawing itself from the position where it was before screen orientation changed, not from the beginning.

Here is my bubble code:

public class Bubble extends View {

    private static final boolean BUBBLING = true; //thread is running to draw

    private Paint paint;
    private ShapeDrawable bubble;

    // coordiantes, radius etc
    private int x;
    private int y;
    private int dx;
    private int dy;
    private int r;
    private int w = 400;
    private int h = 400;

    //handler to invalidate (force redraw on main GUI thread from this thread)
    private Handler handler = new Handler();

    public Bubble(Context context) {
        super(context);

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        w = size.x;
        h = size.y;

        x = w/2;
        y = h/2;
        r = 60;
        dx = 1;
        dy = 1;

        bubble = new ShapeDrawable(new OvalShape());
        bubble.getPaint().setColor(Color.RED);
        bubble.setBounds(0, 0, r, r);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onSizeChanged  (int w, int h, int oldw, int oldh){
        //set bubble parameters (center, size, etc)

        startAnimation();
    }

    public void startAnimation(){
        new Thread(new Runnable() {
            public void run() {
                while (BUBBLING) {
                    moveBubble();

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {

                    }

                    //update by invalidating on main UI thread
                    handler.post(new Runnable() {
                        public void run() {
                            invalidate();
                        }
                    });
                }
            }
        }).start();
    }


    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        // draws bubble on canvas
        canvas.translate(dx, dy);
        bubble.draw(canvas);
        canvas.restore();
    }

    private void moveBubble(){
        dx += 1;
        dy += 1;
        x = x + dx;
        y = y + dy;
        if (bubble.getPaint().getColor() == Color.YELLOW){
            bubble.getPaint().setColor(Color.RED);
        } else {
            bubble.getPaint().setColor(Color.YELLOW);
        }
    }
}

Much appreciated,

推荐答案

If you really want to retain an entire view, you could do something like a lazy load:

public class BubbleFragment extends Fragment {
    Bubble bubble;
    LinearLayout parent;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        setRetainInstance(true);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        parent = new LinearLayout(activity);
        if(bubble == null) {
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    100);
            bubble = new Bubble(getActivity());
            bubble.setLayoutParams(lp);
            bubble.setBackgroundColor(Color.BLUE);
        }
        parent.setOrientation(LinearLayout.VERTICAL);
        parent.addView(bubble);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        parent.removeView(bubble);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return parent;
    }
}

其他推荐答案

In your case you don't need setRetainInstance(true), you just need to save instance variables in onSaveInstanceState() and load them in onCreate(). For your example, something like:

public void onCreate(Bundle b) {
    super.onCreate(b);
    if(b != null) {
        xPos = b.getInt("x");
        yPos = b.getInt("y");
    }
}

public void onSaveInstanceState(Bundle b) {
    super.onSaveInstanceState(b);
    b.putInt("x",xPos);
    b.putInt("y",yPos);
}

By the way, the reason you can't create Bubble in onCreate() is because the Fragment is not fully associated with its Activity until onActivityCreated() is called, which comes after onCreate() is called.