安卓Activity页面跳转(后退到的Activity在页面栈中不存在)

目录

一、问题:页面跳转,后退到的Activity在页面栈中不存在

二、解决方案

1. 重写后退点击事件

2.进出场动画

2.1 设置后退动画

2.2 设置前进动画

3. 解决页面重复问题

(1)将页面设置为singleTask模式

(2)页面向后跳转,销毁当前页面

4. 页面中后退按钮点击,与点击后退键效果保持一致


一、问题:页面跳转,后退到的Activity在页面栈中不存在

之前项目中遇到,一项业务有十几个页面,但是进入点可能不是第一个页面,而可能是之后的任意一个页面,这时候页面栈中并没有中间的几个页面。但是按后退键的时候需要能退回到上一个页面,这个时候实际只能打开一个新的页面。这时后退的动画,也是入场动画,感觉就会比较奇怪。这时我们需要在打开新页面时判断是前进还是后退,并设置对应的自定义进场和出场动画。

逻辑举例,一共有5个页面(1->5),直接进入页面3,这时页面中按“下一步”就跳转到页面4,按返回键或者页面上的返回按钮,就退回页面2。下一步打开新页面是没有任何问题的,但是想要后退,此时页面栈中只有页面3,就需要打开新页面。如果使用默认效果,就会明明逻辑上是后退,实际却是入场动画。

二、解决方案

1. 重写后退点击事件

Activity中点击后退按键时,会调用 onBackPressed() 方法,需要重写的就是这个方法。

(1)首先,重写 onBackPressed() ,改为点击后退键时要处理的内容,即:打开要后退到的新页面;

(2)然后,调用 finish() 方法,销毁当前页面。

示例代码(在第三个页面,点击后退键,跳转到第二个页面)

    @Override
    public void onBackPressed() {
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
        finish();
    }

2.进出场动画

可以使用 overridePendingTransition(int enterAnim, int exitAnim) 方法

overridePendingTransition(int enterAnim, int exitAnim);

此方法需要在 startActivity() 或 finish() 后调用,才能生效。

2.1 设置后退动画

设置后退动画,使用 overridePendingTransition(int enterAnim, int exitAnim) 方法。因为是所有的后退都用的相同的后退动画,所以可以将这个方法放在父类的onBackPressed()中。

BaseActivity中的示例代码

    @Override
    public void onBackPressed() {
        // 设置动画(进场动画, 出场动画)
        overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right);
        super.onBackPressed();
    }

进出场动画放在 res->anim 

enter_from_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="-100%p"
        android:toXDelta="0%p" />
</set>

exit_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="0%p"
        android:toXDelta="100%p" />
</set>

2.2 设置前进动画

页面前进的动画最好和后退的动画对应起来,同样是调用 overridePendingTransition(int enterAnim, int exitAnim) 方法。

示例代码

        btn_next_step.setOnClickListener(v -> {
            Intent intent = new Intent(this, ThirdActivity.class);
            startActivity(intent);
            overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
        });

进出场动画放在 res->anim 

enter_from_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="100%p"
        android:toXDelta="0%p" />
</set>

exit_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="0%p"
        android:toXDelta="-100%p" />
</set>

3. 解决页面重复问题

demo中一共三个页面,逻辑顺序是 1->2->3,实际打开APP时,直接进入的页面3。这是页面栈中只有页面3,后退就要打开新的页面2,页面2后退就要打开新的页面1。实现方法就是上面的两步。但是会出现一个问题,当页面栈中已经存在页面1和页面2时,在后退打开新页面,就会使页面栈中,同一页面出现多个实例。比如页面1,2,3都在页面栈中,这是在页面三点击后退键,打开新的页面2,然后页面3销毁,这是页面栈中有两个页面2。

解决方法有两种

(1)将页面设置为singleTask模式

可以将Activity设置成singleTask模式,这样每个Activity在当前页面栈中就只会有一个实例。设置方法是:在AndroidManifest文件,设置Activity的launchMode属性,为singleTask。

打开某个Activity时,当页面栈中不存在此Activity的实例时,就新建Activity实例,并入栈;如果当页面栈中已经存在此Activity的实例,就把此实例上的Activity全部出栈,使此实例位于页面栈最上层,此Activity也就可以和用户交互了。

代码示例

        <activity
            android:name=".SecondActivity"
            android:launchMode="singleTask" />

(2)页面向后跳转,销毁当前页面

第二种方法,是当页面向后跳转时,打开新页面后,就调用finish()方法,销毁原来的页面。

这样实际上页面栈中只有一个页面,就是当前展示给用户的页面,也就不会有页面重复的问题了。

不过每次向后跳转时,都要调用finish()方法,感觉有些麻烦,不过好处是比较节省内存。

示例代码

        btn_next_step.setOnClickListener(v -> {
            Intent intent = new Intent(this, ThirdActivity.class);
            startActivity(intent);
            overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
            finish();
        });

4. 页面中后退按钮点击,与点击后退键效果保持一致

页面中的后退按钮,点击时,也应该调用 onBackPressed() 方法,来与点击后退键效果保持一致。

不过一般页面中的后退按钮,是在自定义Title中的,而自定义Title一般都是抽象成独立控件。这时就需要在自定义Title中的后退按钮的监听事件中调用 onBackPressed() 方法。当然,这时需要检查控件的上下文是Activity,并转型成Activity后,才可以调用。

做了一个Demo,专门来实现后退按钮的功能,示例代码如下:

package com.song.activitystartdemo;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

public class BackButton extends LinearLayout {
    Context context;

    public BackButton(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public BackButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public BackButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    public BackButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        this.context = context;
        init();
    }

    private void init() {
        View view = LayoutInflater.from(context).inflate(R.layout.btn_back, this);
        Button button = view.findViewById(R.id.button);
        button.setOnClickListener(v -> {
            if (context instanceof Activity) {
                ((Activity) context).onBackPressed();
            }
        });
    }

}

猜你喜欢

转载自blog.csdn.net/sgx1825192/article/details/116139262
今日推荐