Three20研究院之界面之间的转跳与参数的传递(三)

软件与游戏不一样,游戏一般从头至尾都在一个页面中去渲染,而软件开发需要使用高级界面的控件所以开发中必然会存在多个页面。本篇文章的目的主要和朋友们一起探讨Three20软件引擎中如何实现界面的转跳以及参数传递,讲解这部分内容之前了解一下Three20运行的机制。有一句话叫作“默认大于配置”,它的意思就是:我不提供所谓的配置文件方便你来自适应自己的程序,用我的东西你就得按照我的规矩来使用。Three20软件引擎的定义就和这个很像,使用者一旦熟悉它的使用原理按照它的规则来使用,开发软件时会使自己的程序如鱼得水。
回到本章的核心点,Three20源于FaceBook的开源框架,可能是因为FaceBook是一家互联网公司的缘故,就连开源的IOS框架也将互联网的精神发昏的淋漓尽致。通常访问网页时的结构一般是: www.xxx/xxx/xxx/com,它是一个Url的形式,一般修改/xxx/中的参数就可以更改访问的页面,而Three20实现界面之间的转跳和它的原理完全一样,也是通过URL的形式切换访问页面。下面开始本章的教程。

本节一共创建4个界面,并且实现它们之间的相互转跳,本教程中使用到的类如下:

UIStyleSheet:皮肤类,用来修改高级控件默认的皮肤。
StartViewController:第一界面,表示主界面。
InfoViewController:主界面的子界面,表示第二界面。
ThiredViewController:第二界面的子界面,表示第三界面。
TopViewController: 特殊界面,顶层界面。

Three20中需要预先创建所有的游戏界面,所以我们在程序入口方法中去创建这4个界面,由于创建的方法过于复杂,代码中我怕描述不清楚,所以在代码结束的地方添加了详细注释。
01 #import "AppDelegate.h"
02 #import "UIStyleSheet.h"
03 #import "StartViewController.h"
04 #import "InfoViewController.h"
05 #import "ThiredViewController.h"
06 #import "TopViewController.h"
07  
08 @implementation AppDelegate
09  
10 @synthesize window = _window;
11  
12 - (void)dealloc
13 {
14     [_window release];
15     [super dealloc];
16 }
17  
18 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
19 {
20  
21     //创建导航条
22     TTNavigator* navigator = [TTNavigator navigator];
23     navigator.persistenceMode = TTNavigatorPersistenceModeAll;
24     navigator.window = [[[UIWindow alloc] initWithFrame:TTScreenBounds()] autorelease];
25  
26     //注释1
27     [TTStyleSheet setGlobalStyleSheet:[[[UIStyleSheet alloc] init] autorelease]];
28  
29     //注释2
30     TTURLMap* map = navigator.URLMap;
31     //注释3
32     [map from:@"*" toViewController:[TTWebController class]];
33     //注释4
34     [map from:@"tt://StartView" toSharedViewController:[StartViewControllerclass]];
35     //注释5
36     [map from:@"tt://InfoView/(initInfo:)" toViewController:[InfoViewController class]];
37     //注释6
38     [map from:@"tt://ThiredView" toViewController:[ThiredViewController class]];
39     //注释7
40     [map from:@"tt://TopView" toModalViewController:[TopViewController class]];
41  
42     if (![navigator restoreViewControllers])
43     {
44         //注释8
45         [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://StartView"]];
46     
47  
48     return YES;
49 }
50  
51 @end

 

注释1:表示加载当前皮肤类,界面中高级控件的皮肤将应用与UIStyleSheet类中的设定。因为所有与皮肤相关的设置都写在UIStyleSheet类当中,比如按钮的样式、标题栏的颜色等。

注释2:TTURLMap 是一个非常重要的对象,所有相关界面切换的事件都是通过它来设定。举个例子,这里的navigator标题栏就好比PC浏览器中输入网址的地方,然后由Map拼URL访问的地址,表示程序将切换不同的页面。

注释3:TTWebController是Three20自身提供,表示页面将以Web的形式打开。它的功能是在程序中内嵌一个浏览器,比如程序中需要打开一个网址,整个网页内嵌在当前程序中,点击左上角按钮还可以返回。

注释4:@”tt://StartView”表示创建一个页面,该页面指向的视图控制器为StartViewController类。意思是如果程序中如果打开@”tt://StartView”页面,那么该页面展示的内容为StartViewController类中设定的。toSharedViewController方法为设定当前视图控制器的模式为共享模式,共享视图控制器不会每次打开都重新初始化创建,后面会详细说明。

注释5:@”tt://InfoView/(initInfo:)”创建一个指向InfoViewController视图控制器类的页面。(initInfo:)表示如果打开该页面,InitInfo方法为该页面的初始化方法。举个例子, 打开页面@”tt://infoView/1″,然后程序将进入InfoViewController类中的初始化InitInfo方法,传入该方法中的参数为:1。toViewController方法为设定当前视图控制器的模式为普通模式,表示每次打开都会重新初始化创建。

注释6:@”tt://ThiredView”创建一个指向ThiredViewController视图控制器类的页面。

注释7:@”tt://TopView”创建一个指向TopViewController视图控制器类的页面,toMoadViewController表示当前视图控制器模式为悬浮模式,该视图将悬浮在上一个视图控制器之上,直到界面关闭为止。

注释8:表示打开页面@”tt://StartView”,因为它指向StartViewController类,所以程序将执行StartViewController类中页面的初始化操作。

默认大于配置,还是需要一定时间学习,所以到这一步,朋友们只需先混个脸熟,下面我们详细的介绍它们之间的切换方式。

程序入口函数执行完毕将打开StartViewController类,我们先看看这个类的构成部分。.h文件需要引入<Three20/Three20.h>,需要继承TTViewController类,它由Three20封装,非常好用。
StartViewController.h文件
1 #import <Three20/Three20.h>
2  
3 @interface StartViewController : TTViewController
4  
5 @end

StartViewController.m文件

01 #import "StartViewController.h"
02  
03 @implementation StartViewController
04  
05 - (void)viewDidLoad
06 {
07     [super viewDidLoad];
08     //标题栏名称
09     self.title = @"雨松MOMO";
10     //设置视图背景颜色
11     self.view.backgroundColor = [UIColor blackColor];
12     //创建图片视图
13     TTImageView *imageview = [[[TTImageView alloc] initWithFrame:
14                  CGRectMake(100, 10, 120, 120)] autorelease]; 
15  
16     //设置图片视图显示的图片资源
17     imageview.defaultImage = TTIMAGE(@"bundle://0.jpg");
18     //将图片视图加入整个视图当中
19     [self.view addSubview:imageview];
20  
21     //注释1
22     NSArray *buttons = [NSArray arrayWithObjects:
23                         [TTButton buttonWithStyle:@"embossedButton:" title:@"开始游戏"],
24                          [TTButton buttonWithStyle:@"embossedButton:" title:@"继续游戏"],
25                          [TTButton buttonWithStyle:@"embossedButton:" title:@"关于游戏"],
26                          [TTButton buttonWithStyle:@"embossedButton:" title:@"退出游戏"],
27                         nil];
28  
29     for (int i=0; i<buttons.count; i++)
30  
31     {
32         //使用循环将按钮绘制在屏幕当中
33         TTButton *button =  [buttons objectAtIndex:i];
34         //设置字体的大小
35         button.font = [UIFont boldSystemFontOfSize:30];
36         //设置字体的显示区域
37         button.frame = CGRectMake(60, 200 + i*50, 200, 50);
38         //设置字体的标记,通过标记可判断那个按钮点击了
39         button.tag = i;
40         //设置按钮点击相应事件,点击后进入ButtonPressed方法
41         [button addTarget:self action:@selector(ButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
42         //将按钮加入整个视图当中
43         [self.view addSubview: button];
44  
45     }
46  
47 }
48  
49 //按钮点击后将进入这个方法
50 -(void)ButtonPressed:(id)buttonID
51 {
52     //得到导航对象
53     TTNavigator* navigator = [TTNavigator navigator];
54     //获取点击的按钮
55     UIButton *button = (UIButton *)buttonID;
56     //注释2
57     switch (button.tag) {
58         case 0:
59             [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/0"] applyAnimated:YES]];
60             break;
61         case 1:
62             [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/1"] applyAnimated:YES]];
63             break;
64         case 2:
65             [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/2"] applyAnimated:YES] ];
66             break;
67         case 3:
68             [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/3"] applyAnimated:YES]];
69             break;
70         default:
71             break;
72     }
73 }
74 @end

 

注释1:表示在屏幕中共添加了4个按钮,这里比较重要的是按钮的风格。目前4个按钮组件的风格是@”embossedButton:”,而这个参数对应的是UIStyleSheet类中方法,下面请大家看看UIStyleSheet这个类。

UIStyleSheet.h文件
1 #import <Three20/Three20.h>
2  
3 @interface UIStyleSheet : TTDefaultStyleSheet
4  
5 @end

UIStyleSheet.m文件

01 #import "UIStyleSheet.h"
02  
03 @implementation UIStyleSheet
04  
05 //设置标题栏的颜色
06 - (UIColor*)navigationBarTintColor {
07     return [UIColor blueColor];
08 }
09  
10 //按钮的风格
11 - (TTStyle*)embossedButton:(UIControlState)state {
12     if (state == UIControlStateNormal) {
13         return
14         [TTShapeStyle styleWithShape:[TTRoundedRectangleShape shapeWithRadius:8] next:
15          [TTInsetStyle styleWithInset:UIEdgeInsetsMake(0, 0, 1, 0) next:
16           [TTShadowStyle styleWithColor:RGBACOLOR(255,255,255,0) blur:1 offset:CGSizeMake(0, 1) next:
17            [TTLinearGradientFillStyle styleWithColor1:RGBCOLOR(255, 255, 255)
18                                                color2:RGBCOLOR(216, 221, 231) next:
19             [TTSolidBorderStyle styleWithColor:RGBCOLOR(161, 167, 178) width:1 next:
20              [TTBoxStyle styleWithPadding:UIEdgeInsetsMake(10, 12, 9, 12) next:
21               [TTTextStyle styleWithFont:nil color:TTSTYLEVAR(linkTextColor)
22                              shadowColor:[UIColor colorWithWhite:255 alpha:0.4]
23                             shadowOffset:CGSizeMake(0, -1) next:nil]]]]]]];
24     else if (state == UIControlStateHighlighted) {
25         return
26         [TTShapeStyle styleWithShape:[TTRoundedRectangleShape shapeWithRadius:8] next:
27          [TTInsetStyle styleWithInset:UIEdgeInsetsMake(0, 0, 1, 0) next:
28           [TTShadowStyle styleWithColor:RGBACOLOR(255,255,255,0.9) blur:1 offset:CGSizeMake(0, 1) next:
29            [TTLinearGradientFillStyle styleWithColor1:RGBCOLOR(225, 225, 225)
30                                                color2:RGBCOLOR(196, 201, 221) next:
31             [TTSolidBorderStyle styleWithColor:RGBCOLOR(161, 167, 178) width:1 next:
32              [TTBoxStyle styleWithPadding:UIEdgeInsetsMake(10, 12, 9, 12) next:
33               [TTTextStyle styleWithFont:nil color:[UIColor whiteColor]
34                              shadowColor:[UIColor colorWithWhite:255 alpha:0.4]
35                             shadowOffset:CGSizeMake(0, -1) next:nil]]]]]]];
36     else {
37         return nil;
38     }
39 }
40  
41 @end

 

-(UIColor*)navigationBarTintColor :该方法用来设定导航栏颜色,目前设置它的颜色为蓝色。
-(TTStyle*)embossedButton:(UIContorlState)state:这个方法就比较重要了,请回到StartViewController类中,刚刚在设定按钮风格的时候参数名称与这个方法名称一致、表示按钮将采取这个方法中的显示风格。切记一定要设定这个风格类应用于整个工程。还记得在AppDelegate类中执行的方法吗? [TTStyleSheet setGlobalStyleSheet:[[[UIStyleSheet alloc] init] autorelease]];该方法表示程序将采取UIStyleSheet类中的风格,这行代码一定要写,否则将不会采取UIStyleSheet类中的风格,使用系统默认风格。UIStyleSheet类中不止可以设定按钮的风格,整个IOS所有高级控件的显示风格都可以设定,官方的文档中已经详细说明:

http://api.three20.info/interface_t_t_default_style_sheet.php


拓展学习:如下图所示,Three20一共封装了9中按钮的样式,足够开发中使用,而本例中我们使用到的按钮样式就是”Embossed Button”。大家也可根据自己的喜好去设定不同的按钮样式,按钮的官方例子写在“Catalog”工程当中。详细按钮的代码写在ButtonTestController.m文件中。

 

 

高级控件风格的教学就先到此为止,本文讨论的重点并不是它,请大家再次回到StartViewController.m类当中。

注释2:由于界面中共设置了4个按钮,为了让这4个按钮共用一个初始事件的方法,可在创建按钮时为它添加一个标记。4个按钮中点击任意按钮后都会进入ButtonPressed方法,然后通过id的到当前点击按钮的对象,使用button.tag可判断那个按钮被点击。

请注意看下方的switch方法,通过用户点击不同的按钮将打开@”tt://InfoView/X”页面,applyAnimated:YES表示播放切换页面的动画,不写开始动画效果也可,只是切换页面时将不在有切换动画。

01 switch (button.tag) {
02     case 0:
03         [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/0"] applyAnimated:YES]];
04         break;
05     case 1:
06         [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/1"] applyAnimated:YES]];
07         break;
08     case 2:
09         [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/2"] applyAnimated:YES] ];
10         break;
11     case 3:
12         [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://InfoView/3"] applyAnimated:YES]];
13         break;
14     default:
15         break;
16 }

 

如下图所示,在StartViewController类中点击按钮“开始游戏”、“机修游戏”、“关于游戏”、“退出游戏”将分别进入页面:@“tt://InfoView/0” 

@“tt://InfoView/1” 

@“tt://InfoView/2” @”tt://InfoView/3″,它们对应的视图控制器为”InfoViewController”。

 

根据它们的关系可得:InfoViewController为StartViewController的子页面。

InfoViewController.h文件:

1 #import <Three20/Three20.h>
2  
3 @interface InfoViewController : TTViewController
4 {
5      //页面的ID
6      int pageID;
7 }
8  
9 @end

InfoViewController.m文件:

01 #import "InfoViewController.h"
02  
03 @implementation InfoViewController
04  
05 //注释1
06 - (id)initInfo:(int)ID {
07     if (self = [super init]) {
08         pageID = ID;
09     }
10     return self;
11 }
12  
13 - (void)viewDidLoad
14 {
15     [super viewDidLoad];
16     //根据上级页面点击的按钮而显示标题
17     switch (pageID) {
18         case 0:
19             self.title = @"开始游戏页面";
20             break;
21         case 1:
22             self.title = @"继续游戏页面";
23             break;
24         case 2:
25             self.title = @"关于游戏页面";
26             break;
27         case 3:
28             self.title = @"退出游戏页面";
29             break;
30         default:
31             break;
32     }
33  
34     self.view.backgroundColor = [UIColor blackColor];
35     //创建图片视图
36     TTImageView *imageview = [[[TTImageView alloc] initWithFrame:
37                               CGRectMake(100, 10, 120, 120)]autorelease];
38     imageview.defaultImage = TTIMAGE(@"bundle://1.jpg");
39     [self.view addSubview:imageview];
40  
41     //添加按钮
42     TTButton *button =  [TTButton buttonWithStyle:@"embossedButton:" title:@"测试按钮"];
43     button.font = [UIFont boldSystemFontOfSize:30];
44     button.frame = CGRectMake(60, 200, 200, 50);
45     [button addTarget:self action:@selector(ButtonPressed) forControlEvents:UIControlEventTouchUpInside];
46     [self.view addSubview: button];
47  
48 }
49  
50 -(void)ButtonPressed
51 {
52     //按钮点击后开启ThiredView页面
53     TTNavigator* navigator = [TTNavigator navigator];
54     [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://ThiredView"] applyAnimated:YES]]; 
55  
56 }
57  
58 @end

注释1:还记得在StartViewController类中点击按钮后,打开URL:@”tt://InfoView/0″类似的页面吗?大家在回想一下在AppDelegate类中声明所有页面的方法中。

 

 

 [map from:@"tt://InfoView/(initInfo:)" toViewController:[InfoViewController class]];  

如果通过@”tt://InfoView/0″进入InfoViewController类,在-(id)initInfo:(int)ID方法中,ID的值就是0,如果@“tt://InfoView/1”进入InfoViewController类,那么对应ID的值就是1。以此类推,通过这样的方法就能在不同页面之间传递数值。

 

本例在进入InfoViewController页面中记录上一级界面中点击按钮的ID,然后在ViewDidLoad方法中去编辑当前标题栏中显示的标题内容,实现通过参数来区分显示的页面信息。然后在当前页面中添加一个按钮,点击该按钮后在此将页面切换至第三级页面中。

 

 

点击“测试按钮后”程序将进入第三级页面,进入@”tt://ThiredView”对应的ThiredViewController中。

ThiredViewController.h文件

1 #import <Three20/Three20.h>
2  
3 @interface ThiredViewController : TTViewController
4  
5 @end

ThiredViewController.m文件。

01 #import "ThiredViewController.h"
02  
03 @implementation ThiredViewController
04  
05 - (void)viewDidLoad
06 {
07     [super viewDidLoad];
08  
09     self.view.backgroundColor = [UIColor blackColor];
10     //创建图片视图
11     TTImageView *imageview = [[[TTImageView alloc] initWithFrame:
12                               CGRectMake(100, 10, 120, 120)] autorelease];
13     imageview.defaultImage = TTIMAGE(@"bundle://2.jpg");
14     [self.view addSubview:imageview];
15  
16     TTButton *button0 =  [TTButton buttonWithStyle:@"embossedButton:" title:@"返回主界面"];
17     button0.font = [UIFont boldSystemFontOfSize:30];
18     button0.frame = CGRectMake(60, 200, 200, 50);
19     [button0 addTarget:self action:@selector(ReturnStartView) forControlEvents:UIControlEventTouchUpInside];
20     [self.view addSubview: button0];
21  
22     TTButton *button1 =  [TTButton buttonWithStyle:@"embossedButton:" title:@"打开顶窗口"];
23     button1.font = [UIFont boldSystemFontOfSize:30];
24     button1.frame = CGRectMake(60, 250, 200, 50);
25     [button1 addTarget:self action:@selector(OpenTopView) forControlEvents:UIControlEventTouchUpInside];
26     [self.view addSubview: button1];
27 }
28  
29 -(void)dealloc
30 {
31     [super dealloc];
32     [[TTNavigator navigator] setDelegate:nil];
33  
34 }
35  
36 -(void)ReturnStartView
37 {
38     //注释1
39     TTNavigator* navigator = [TTNavigator navigator];
40     [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://StartView" ] applyAnimated:YES]]; 
41  
42 }
43  
44 -(void)OpenTopView
45 {
46     //注释2
47     TTNavigator* navigator = [TTNavigator navigator];
48     [navigator openURLAction:[[TTURLAction actionWithURLPath:@"tt://TopView"] applyAnimated:YES]];
49  
50 }
51  
52 @end

 

 

注释1:在屏幕中点击“返回主界面”按钮后,将切换程序页面进入@”tt://StartView” 也就是回到主页面。如下图所示,界面正常的回到了主页面。到这里大家可能会有疑惑。为什么界面的左上角没有返回的按钮。原因简单,回到AppDelegate类中,在入口方法中我们在创建主页面中使用的方法是:

[map from:@"tt://StartView" toSharedViewController:[StartViewController class]];   

 ”toSharedViewController”它表示共享创建控制器,所以页面再次切换至StartViewController类,它不会重新加载页面,所以左上角不会有返回按钮。

 


带着上面这个疑问,请大家将AppDelegate.m中的方法修改一下。

修改前: [map from:@"tt://StartView" toSharedViewController:[StartViewController class]];     

修改后:[map from:@"tt://StartView" toViewController:[StartViewController class]]; 

如下图所示,返回按钮出现在屏幕当中,显然这不是一个好办法,因为使用toViewController表示页面将会再次加载一次,所以当前的主菜单并不是最开始创建的主菜单,而成为了ThiredViewController的子窗口。

 

 

请大家再次回到ThiredViewController当中。

注释2:在界面中点击“打开顶层窗口”按钮,程序页面将切换至@”tt://TopView”,也就是打开TopViewController这个类。为什么说它是顶层窗口?原因是它不同于之前的窗口,之前的窗口左上角都会有返回按钮,点击返回后可回到上一级窗口,而它仅仅是覆盖了上一级窗口,所以它没有左上角的返回按钮。然而这一些的设置都在AppDelegate当中:

 [map from:@"tt://TopView" toModalViewController:[TopViewController class]]; 

toModalViewController方法表示当前界面为一个覆盖类型的页面,打开该页面后将覆盖原有页面。

TopViewController.h文件

 

1 #import <Three20/Three20.h>
2  
3 @interface TopViewController : TTViewController
4  
5 @end

TopViewController.m文件

01 #import "TopViewController.h"
02  
03 @implementation TopViewController
04  
05 - (void)viewDidLoad
06 {
07     [super viewDidLoad];
08  
09     self.title=@"顶窗口页面";
10     self.view.backgroundColor = [UIColor blackColor];
11     //创建图片视图
12     TTImageView *imageview = [[[TTImageView alloc] initWithFrame:
13                                CGRectMake(100, 10, 120, 120)] autorelease];
14     imageview.defaultImage = TTIMAGE(@"bundle://3.jpg");
15     [self.view addSubview:imageview];
16  
17     TTButton *button0 =  [TTButton buttonWithStyle:@"embossedButton:" title:@"关闭页面"];
18     button0.font = [UIFont boldSystemFontOfSize:30];
19     button0.frame = CGRectMake(60, 200, 200, 50);
20     [button0 addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
21     [self.view addSubview: button0];
22 }
23  
24 - (void)dismiss
25 {
26     //关闭窗口,包括关闭动画
27     [self dismissModalViewControllerAnimated:YES];
28  
29 }
30  
31 @end

如下图所示,顶层窗口页面已经打开,它的打开动画也不同于其它窗口,打开时动画方向向上播放。左上角不会出现返回的按钮。在屏幕中点击“关闭页面按钮”将关闭最上层界面,关闭时动画方向向下播放。

 

 

仔细想想通过这篇文章我们学习了Three20中打开界面的三种方式,这也是最常用的方式。我相信仔细阅读过这篇博文的朋友应该会爱上Three20了吧。做IOS软件的话,就用它吧。通过这个例子大家应该已经能区分toSharedViewController 与toViewController 以及toModalViewController切换界面之间的区别的吧,一口气写了这么多,累得够呛!!哇咔咔~

最后欢迎各位盆友可以和MOMO一起讨论Three20软件开发,如果你觉得看得不清楚,MOMO附带上本章的源码下载,希望大家可以一起学习 哈哈~。哇咔咔~ MOMO愿和 大家好好学习,大家一起进步哈~!!!


(下载后必需搭建three20环境成功后才能运行~ 因为three20为引用加载,所以程序路径都是我本机的请见谅!或者你可可以将你的Three20路径修改的和我一样就可以直接运行啦,我的路径是:User (用户) -> Share(共享)->Three20)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值