保留片段
Retaining Fragment
我正在编写一个可以在 Canvas 上绘制气泡的应用程序。
我有 MainActivity,它的布局是一个简单的 LinearLayout,我将其用作片段的容器。
我的片段没有 xml 布局,因为我在 Canvas 上绘图,所以我以编程方式设置其布局,如下所示:
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);
}
}
}
非常感谢,
在你的情况下你不需要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() 中创建 Bubble 的原因是因为在调用 onActivityCreated() 之前,Fragment 没有与其 Activity 完全关联,这在调用 onCreate() 之后出现。
如果你真的想保留整个视图,你可以做一些像延迟加载这样的事情:
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;
}
}
我正在编写一个可以在 Canvas 上绘制气泡的应用程序。 我有 MainActivity,它的布局是一个简单的 LinearLayout,我将其用作片段的容器。 我的片段没有 xml 布局,因为我在 Canvas 上绘图,所以我以编程方式设置其布局,如下所示:
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);
}
}
}
非常感谢,
在你的情况下你不需要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() 中创建 Bubble 的原因是因为在调用 onActivityCreated() 之前,Fragment 没有与其 Activity 完全关联,这在调用 onCreate() 之后出现。
如果你真的想保留整个视图,你可以做一些像延迟加载这样的事情:
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;
}
}