iOS和Android对比系列(二):页面跳转和传参

iOS和Android对比系列(二):页面跳转和传参

[TOC]

iOS

跳转页面方式

  • UIViewController
    • present: - (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);
    • dismiss: - (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);
  • UINavigationController
    • push: - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
    • pop:
      • - (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;: 返回到上一个页面
      • - (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;: 返回到指定页面
      • - (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;: 返回到根控制器
  • UITabBarController: 系统自己处理,也可自己手动选中
    • @property(nonatomic) NSUInteger selectedIndex;

页面传递参数

正向传递: 在 .h 文件中设置需要传递的参数

@interface MHConfirmOrderVC : KindergartenBase
@property (nonatomic, strong) ProductObject *product;
@end

注意:正向传递的参数在init方法中获取不到的,在loadView中以及后续的生命周期中可以获取到

反向传递:

方法一:使用代理(协议)

例子:

  • MHMessageListVC 正向传递参数给 MHMessageDetailVC
  • MHMessageDetailVC 反向传递参数给 MHMessageListVC

MHMessageListVC 代码

@interface MHMessageListVC ()<MHMessageDetailVCDelegate>
// ......
@end

@implementation MHMessageListVC

// ......

// 正向传递参数和跳转控制器
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    MHMessageCellLayout *cellLayout = [self.viewModel.dataSource objectAtIndex:indexPath.section];

    MHMessageDetailVC *vc = [[MHMessageDetailVC alloc] init];
    vc.index = indexPath.section; // 传递参数
    vc.delegate = self; // 设置代理
    [self.navigationController pushViewController:vc animated:YES]; // 跳转控制器
}

// 接受反向传递的参数结果
- (void)messageDetailDidLook:(NSInteger)index {
    // ......
}

@end

MHMessageDetailVC 代码

// .h 文件
@protocol MHMessageDetailVCDelegate <NSObject>
@optional
/// 消息已读
- (void)messageDetailDidLook:(NSInteger)index;
@end

@interface MHMessageDetailVC : MHBaseViewController

/// 操作的索引
@property (nonatomic, assign) NSInteger index;
/// 代理
@property (nonatomic, weak, nullable) id<MHMessageDetailVCDelegate> delegate;

@end

// .m 文件
@implementation MHMessageDetailVC

// ......

// 在 viewDidLoad 方法只是一个示例,根据实际情况调用
- (void)viewDidLoad {
    [super viewDidLoad];

    // 反向传递参数,和参数访问
    if (self.delegate && [self.delegate respondsToSelector:@selector(messageDetailDidLook:)]) {
        [self.delegate messageDetailDidLook:_index];
    }
}

@end

方法二:遍历控制器进行设置

思路是获取到当前的控制器栈,然后进行遍历,找到目标控制器,然后进行处理,例子如下:

UIViewController *popToController = nil;
NSArray *controllers = self.navigationController.viewControllers;
for (UIViewController *controller in controllers) {
  if ([NSStringFromClass([controller class]) isEqualToString:@"MHNewWebViewVC"]) {
      popToController = controller;
      break;
  }
}
if (popToController) {
  // 刷新页面
  if ([popToController isKindOfClass:[MHNewWebViewVC class]]) {
      MHNewWebViewVC *popVC = (MHNewWebViewVC *)popToController;
      [popVC reloadWebView]; // 这里除了刷新页面,还可以传递参数(修改属性的值),调用方法等等
  }
  [self.navigationController popToViewController:popToController animated:YES];
} else {
    // ..... 父类方法
}

Android

Activity跳转页面和传参,使用 Intent

格式:

Intent intent = new Intent(当前Activity.this, 目标.class);
startActivity(intent);

跳转页面(不传递参数)

Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);

跳转页面 (传递简单的参数) putExtra()

使用IntentputExtra() 方法

Intent intent = new Intent(MainActivity.this, LoginActivity.class);
intent.putExtra("key", "value");
startActivity(intent);

目标LoginActivityonCreate()方法中获取

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        Log.e(TAG, "onCreate -- " );
        String value = getIntent().getStringExtra("key");
        Log.e(TAG, "getIntent 结果 : " + value );
    }

打印结果:

E/LoginActivity: getIntent 结果 : value

注意:putget值类型需要对应

跳转页面 (传递复杂的参数) BundleputSerializable()

使用 BundleputSerializable()

// 1、自定义的类,实现 Serializable 接口
public class VipService implements Serializable {
    private Long productId;
    private String productName;

    public Long getProductId() {
        return productId;
    }

    public void setProductId(Long productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }
}

// 2、跳转传参
VipService vipService = new VipService();
vipService.setProductId((long) 100);
vipService.setProductName("测试商品");

Bundle bundle = new Bundle();
bundle.putSerializable("vipKey", vipService);

Intent intent = new Intent(MainActivity.this, LoginActivity.class);
intent.putExtra("key", "value");
intent.putExtras(bundle); // 传递自定义类对象
startActivity(intent);

// 3、获取传递的参数
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_login);

   Log.e(TAG, "onCreate -- " );
   String value = getIntent().getStringExtra("key");
   Log.e(TAG, "getIntent 结果 : " + value );

   VipService vipService = (VipService) getIntent().getSerializableExtra("vipKey");
   Log.e(TAG, "vipService - productId : " + vipService.getProductId());
   Log.e(TAG, "vipService - productName : " + vipService.getProductName());
}

打印结果:

E/LoginActivity: getIntent 结果 : value
    vipService - productId : 100
    vipService - productName : 测试商品

跳转页面 (获取结果)

  • 使用方法 startActivityForResult()
  • 监听结果方法 onActivityResult()
  • 两个code: 请求requestCode和结果resultCode

例子:

// 1、使用  startActivityForResult() 方法进行跳转 activity, MainActivity 跳转到 LoginActivity 
VipService vipService = new VipService();
vipService.setProductId((long) 100);
vipService.setProductName("测试商品");

Bundle bundle = new Bundle();
bundle.putSerializable("vipKey", vipService);

Intent intent = new Intent(MainActivity.this, LoginActivity.class);
intent.putExtra("key", "value");
intent.putExtras(bundle); // 传递自定义类对象
//  startActivity(intent);
startActivityForResult(intent, LoginActivity.REQUEST_CODE); // 需要获取返回结果

// 2、监听返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   if (requestCode == LoginActivity.REQUEST_CODE) {
       if (resultCode == LoginActivity.RESULT_CODE) {
           String name = data.getStringExtra("name");
           String desc = data.getStringExtra("desc");

           Log.e(TAG, "接受到页面传参啦 ---- ");
           Log.e(TAG, "name=" + name);
           Log.e(TAG, "desc=" + desc);
       }
   }
}

// 3、请求码和返回码
public static int REQUEST_CODE = 100;
public static int RESULT_CODE = 1000;

// 4、LoginActivity 返回的时候 向 MainActivity 传递参数
Intent intent = new Intent ();
intent.putExtra("name", "返回啦");
intent.putExtra("desc", "页面传参描述");
setResult(RESULT_CODE, intent);
finish();

打印结果:

E/MainActivity: 接受到页面传参啦 ---- 
    name=返回啦
    desc=页面传参描述

对比

  • 正向传递参数的获取:
    • iOS 需要在 loadView 方法中以及之后的生命周期方法中都可以获取到,一般是viewDidLoad
    • Android 需要在 onCreate() 方法中获取
  • 反向传递参数:
    • iOS使用代理协议,后者进行遍历
    • Android使用 startActivityForResult()

iOS传递简单或对象都是和控制器UIViewController挂钩的
Android传递参数都是通过Intent,自定义的类对象还需要使用Bundle传递;

推荐阅读更多精彩内容