iOS 在应用中嵌入网页一个购物网页可以吗

现有iOS项目中嵌入几个 React Native 页面 - 简书
现有iOS项目中嵌入几个 React Native 页面
具体步骤参考官方文档,环境弄好后,工程目录如下
原iOS项目被放在了根目录的iOS文件夹下(没做安卓,所以没有安卓的路径)
React Native 的iOS入口是 index.ios.js
其他 React Native 的代码放在了 component文件夹
main.jsbundle 为我们所写 React Native 代码的集合,发布时才生成(或方便真机调试)
RN入口index.ios.js
'use strict'; //使用严格模式
import React, { Component } from 'react';
AppRegistry,//用于注册组件
StyleSheet,//使用样式
NavigatorIOS,//导航控制器
TouchableHighlight,//点击效果
NativeModules//调用native方法
} from 'react-native';
import Repayment from './component/repayment';
import SettlementAccountList from './component/SettlementAccountList';
export default class MECRM extends Component {
_handleNavigationBackRequest() {
var RNBridge = NativeModules.RNB
RNBridge.back();
_settlementAccountList() {
var status = this.props["status"];
if (status === 0 || status === 3) {
this.refs['nav'].push({
title: '返款人信息表',
component: SettlementAccountList,
barTintColor: '#7B9DFD',
tintColor: 'white',
passProps: {
render() {
&NavigatorIOS
initialRoute={{
component: Repayment,//注册的组件名一定要大写
title: '返款申请',
rightButtonIcon: require('image!contacts'),
leftButtonTitle: '返回',
onLeftButtonPress: () =& this._handleNavigationBackRequest(),
onRightButtonPress: () =& this._settlementAccountList(),
passProps: {
orderid: this.props["orderid"],
status: this.props["status"],
price: this.props["price"]
barTintColor: '#7B9DFD'
style={{flex: 1}}
itemWrapperStyle={styles.itemWrapper}
tintColor="white"
titleTextColor ='white'
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
AppRegistry.registerComponent('RNBackApply', () =& MECRM);
index.ios.js作为RN代码入口,关键点是 NavigatorIOS 标签:
ref='nav',把 NavigatorIOS 对象标记为‘nav’方便调用,类似iOS开发中的tag,this.refs['nav']便能找到 NavigatorIOS 对象。(弥补this传递的麻烦)
initialRoute 初始化路由,这里初始化起始页为Repayment,然后点击左右按钮分别执行handleNavigationBackRequest(返回native页面)、settlementAccountList(跳转到返款账号列表页面)
passProps,传递 orderid、status、price到Repayment页面(此处这3个参数是从naive传递到index.ios.js,index.ios.js再传递给了Repayment)
native入口
let jsCodeLocation = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")
let mockData:NSDictionary = ["orderid": self.orderId,
"status" : self.orderDetailModel.status,
: self.orderDetailModel.cost]
let rootView = RCTRootView(bundleURL: jsCodeLocation,
moduleName: "RNBackApply",
initialProperties: mockData as [NSObject : AnyObject],
launchOptions: nil)
let vc = UIViewController()
vc.view = rootView
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.pushViewController(vc, animated: true)
jsCodeLocation RN执行文件路径,这里的路径为开发时使用,发布时需更换为main.jsbundle的路径
mockData为从native传递到RN的数据
moduleName: "RNBackApply"与index.ios.js中registerComponent('RNBackApply', () =& MECRM)对应
3.构建页面
前面提到起始页为Repayment,那么Repayment是怎么实现如上图的喃?以下为简要实现
'use strict';
import React, { Component } from 'react';
StyleSheet,
ScrollView,
TouchableHighlight,//整块区域有按压效果
TouchableOpacity,//文字有按压效果
TextInput,
NativeModules,
DeviceEventEmitter//通知
} from 'react-native';
import PayTypeChoice from './PayTypeChoice';//注意路径是以当前文件为准
export default class repayment extends Component {
constructor(props) {
super(props);
var defaultMoney = (this.props["price"]*0.2&0.01?0.01:this.props["price"]);
this.state = {events: {
orderId: this.props["orderid"].toString(),
account: '',
accountType: 1,
accountName: '',
bankName: '',
branchName: '',
money: defaultMoney.toString(),
status: '',
remark: '',
failReason: '',
this._applySettlementRequest();
this._accountInfoChoiced();
_accountInfoChoiced() {
this.subscription = DeviceEventEmitter.addListener('accountInfoChoiced',(accountInfo) =& {
var newEvents = this.state.
.account = accountInfo.
.accountName = accountInfo.accountN
.accountType = accountInfo.accountT
.bankName = accountInfo.bankN
.branchName = accountInfo.branchN
this.setState({events: newEvents});
_renderRow(title: string, subTitle: string, placeholder: string, onChangeText: Function, maxLength: int) {
var status = this.props["status"];
&View style={styles.row}&
&Text style={styles.rowText}&
{(status === 0 || status === 3)?
&TextInput
style={styles.rowInputText}
autoCapitalize={'none'}
maxLength = {maxLength}
onChangeText={onChangeText}
value={subTitle}
placeholder={placeholder}
selectionColor='#0064FF'
clearButtonMode={'while-editing'}
returnKeyType={'done'}
&TextInput
style={styles.rowInputText}
autoCapitalize={'none'}
onChangeText={onChangeText}
value={subTitle}
placeholder={placeholder}
selectionColor='#0064FF'
clearButtonMode={'while-editing'}
returnKeyType={'done'}
editable={false}
&View style={styles.separator} /&
_renderButton(onPress: Function) {
var status = this.props["status"];
var buttonString = '申请返款';
switch (status) {
var buttonString = '申请返款';
var buttonString = '返款处理中';
var buttonString = '已返款';
var buttonString = '已拒绝,重新申请';
var buttonString = '待审核';
var canPost =
var orderInfo = this.;
if ((status === 0 || status === 3) && orderInfo.accountName.length & 0 && orderInfo.account.length & 0 && orderInfo.money.length & 0 ) {
if (orderInfo.accountType === 2) {
if (orderInfo.bankName.length & 0 && orderInfo.branchName.length & 0) {
&View style={styles.container}&
&TouchableOpacity style={styles.button} onPress={onPress}&
&Text style={styles.buttonText}&{buttonString}&/Text&
&/TouchableOpacity&
&View style={styles.disableButton}&
&Text style={styles.buttonText}&{buttonString}&/Text&
_onButtonPress() {
var orderInfo = this.;
orderInfo.money = Number(orderInfo.money*100);
if(isNaN(orderInfo.money)){
AlertIOS.alert(
'请输入正确的返款金额',
var orderPrice = (this.props["price"]*100);
if (orderInfo.money & orderPrice*0.8) {
AlertIOS.alert(
'当前返款大于支付金额的80%,是否继续?',
{text: '返回修改'},
{text: '继续发起', onPress: () =& {
var RNBridge = NativeModules.RNB
RNBridge.setSettlement(orderInfo,(error, events) =& {
if (error) {
// console.error(error);
this._handleNavigationBackRequest();
var RNBridge = NativeModules.RNB
RNBridge.setSettlement(orderInfo,(error, events) =& {
if (error) {
// console.error(error);
this._handleNavigationBackRequest();
_applySettlementRequest() {
var status = this.props["status"];
// status参数说明
if (status === 0) {
var RNBridge = NativeModules.RNB
var orderid = this.props["orderid"].toString();
RNBridge.applySettlement(orderid,(error, events) =& {
if (error) {
console.error(error);
.money = (.money/100).toString();
this.setState({events: events});
render() {
var orderInfo = this.;
var status = this.props["status"];
&ScrollView style={styles.list}&
&View style={styles.line}/&
&View style={styles.group}&
{this._renderPayTypeRow(() =& {
this.props.navigator.push({
title: '返款方式',
component: PayTypeChoice,
barTintColor: '#7B9DFD',
tintColor: 'white',
passProps: {
accountType: this..accountType,
getPayType:(accountType)=&{
var newEvents = this.state.
.accountType = accountT
this.setState({events: newEvents});
{this._renderRow('姓名', orderInfo.accountName, '请输入姓名', (accountName) =& {
var newEvents = this.state.
.accountName = accountN
this.setState({events: newEvents});
{(orderInfo.accountType === 2)?
{this._renderRow('开户银行', orderInfo.bankName, '请输入开户银行', (bankName) =& {
var newEvents = this.state.
.bankName = bankN
this.setState({events: newEvents});
{this._renderRow('开户支行', orderInfo.branchName, '请输入开户支行', (branchName) =& {
var newEvents = this.state.
.branchName = branchN
this.setState({events: newEvents});
&View style={styles.line}/&
{this._renderButton(() =& {
this._onButtonPress();
&/ScrollView&
const styles = StyleSheet.create({
constructor 初始化数据,这里的数据结构和网络请求结果保持一致。
renderRow 函数以及被省略掉的其他renderXXXRow函数只是让总的render函数没那么臃肿,返回一些JSX片段,在构建界面中根据不同条件展示不同样式是常见需求,但是JSX中不支持 if.else,只支持三目运算符?:,在上面代码中多次用到。
需求功能1:点击返款方式,跳转到返款方式选择页面,然后把选择的方式回传。
这里页面传值采用的方式是将修改返款方式后的操作作为一个函数传递给下一个页面,实现如下。
Repayment.js
{this._renderPayTypeRow(() =& {
this.props.navigator.push({
title: '返款方式',
component: PayTypeChoice,
barTintColor: '#7B9DFD',
tintColor: 'white',
passProps: {
accountType: this..accountType,
getPayType:(accountType) =& {
var newEvents = this.state.
.accountType = accountT
this.setState({events: newEvents});
PayTypeChoice.js
render() {
&ScrollView style={styles.list}&
&View style={styles.line}/&
&View style={styles.group}&
{this._renderRow('支付宝', this.state.alipay,() =& {
this.props.getPayType(1);
this.props.navigator.popToTop()
&View style={styles.separator} /&
{this._renderRow('银行卡', this.state.bankcard,() =& {
this.props.getPayType(2);
this.props.navigator.popToTop()
&View style={styles.line}/&
&/ScrollView&
Repayment.js中的getPayType就是传递到下一个页面,当返款方式选择后以执行的函数。在PayTypeChoice.js中当cell点击的时候将返款方式作为参数传入,例如this.props.getPayType(1),就将返款方式设置为了支付宝。
需求功能2:点击右上角图标,跳转到返款账号列表页,然后把选择的账号信息带回来填充页面。
如之前所述,点击图标跳转的逻辑是写在index.ios.js文件中的
_settlementAccountList() {
var status = this.props["status"];
if (status === 0 || status === 3) {
this.refs['nav'].push({
title: '返款人信息表',
component: SettlementAccountList,
barTintColor: '#7B9DFD',
tintColor: 'white',
passProps: {
想通过刚才传递函数的方式达到页面传值,那么index.ios.js就要先获取到Repayment用于回调的函数,然后再传递给SettlementAccountList。很麻烦,并且我尝试了一下没成功。这种时候,通知就显得非常简单粗暴了,运用React Native中的通知组件DeviceEventEmitter,页面传值都不是事儿。
当账号信息被选择时在SettlementAccountList中发送通知
_onPressCell(rowData: string) {
this.props.navigator.popToTop()
DeviceEventEmitter.emit('accountInfoChoiced', rowData);
在Repayment中接收通知
_accountInfoChoiced() {
this.subscription = DeviceEventEmitter.addListener('accountInfoChoiced',(accountInfo) =& {
var newEvents = this.state.
.account = accountInfo.
.accountName = accountInfo.accountN
.accountType = accountInfo.accountT
.bankName = accountInfo.bankN
.branchName = accountInfo.branchN
this.setState({events: newEvents});
需求功能3:在进入页面时拉取之前填写的返款信息,点击左上的返回按钮回到Native页面,以及返款账号信息页面拉取已有的信息。这3点都是调用的Native方法。虽然RN也有网络请求方法,但是APP中的网络请求会有公共参数、公共的鉴权方法、错误处理等,所以网络请求还是选择走Native的好。
创建待RN调用的Native方法的步骤,在官方文档中也讲得很清楚,这里贴出我写的代码片段(因为Objective-C写着更方便就没用Swift,偷懒了一下)
RNBridge.m
#import "RNBridge.h"
#import &UIKit/UIKit.h&
#import &MECRM-Swift.h&
@implementation RNBridge
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(back)
dispatch_async(dispatch_get_main_queue(), ^{
UITabBarController *tabvc = (UITabBarController *)[self getCurrentVC];
UINavigationController *navi = [tabvc selectedViewController];
navi.navigationBarHidden = NO;
[navi popViewControllerAnimated:YES];
//获取返款信息
RCT_EXPORT_METHOD(applySettlement:(NSString *)orderID callback:(RCTResponseSenderBlock)callback)
dispatch_async(dispatch_get_main_queue(), ^{
UITabBarController *tabvc = (UITabBarController *)[self getCurrentVC];
UINavigationController *navi = [tabvc selectedViewController];
UIViewController * vc = navi.viewControllers.lastO
[vc startAnimating];
NSString *path = [NSString stringWithFormat:@"/order/%@/applySettlement",orderID];
[NetworkTool GET:path parameters:nil successHandler:^(id _Nonnull result) {
[vc stopAnimating];
callback(@[[NSNull null], result]);
} failureHandler:^(NSError * _Nullable error) {
[vc stopAnimating];
callback(@[error.localizedDescription, [NSNull null]]);
//设置返款信息
RCT_EXPORT_METHOD(setSettlement:(NSDictionary *)orderInfo callback:(RCTResponseSenderBlock)callback)
dispatch_async(dispatch_get_main_queue(), ^{
UITabBarController *tabvc = (UITabBarController *)[self getCurrentVC];
UINavigationController *navi = [tabvc selectedViewController];
UIViewController * vc = navi.viewControllers.lastO
[vc startAnimating];
NSString *orderID = orderInfo[@"orderId"];
NSString *path = [NSString stringWithFormat:@"/order/%@/applySettlement",orderID];
[NetworkTool POST:path parameters:orderInfo successHandler:^(id _Nonnull result) {
[vc stopAnimating];
callback(@[[NSNull null], result]);
} failureHandler:^(NSError * _Nullable error) {
[vc stopAnimating];
callback(@[error.localizedDescription, [NSNull null]]);
//返款人信息表
RCT_EXPORT_METHOD(getSettlementAccount:(NSInteger)start callback:(RCTResponseSenderBlock)callback)
dispatch_async(dispatch_get_main_queue(), ^{
UITabBarController *tabvc = (UITabBarController *)[self getCurrentVC];
UINavigationController *navi = [tabvc selectedViewController];
UIViewController * vc = navi.viewControllers.lastO
[vc startAnimating];
NSString *path = [NSString stringWithFormat:@"/order/getSettlementAccount?start=%ld&limit=%d",(long)start,100];
[NetworkTool GET:path parameters:nil successHandler:^(id _Nonnull result) {
[vc stopAnimating];
callback(@[[NSNull null], result]);
} failureHandler:^(NSError * _Nullable error) {
[vc stopAnimating];
callback(@[error.localizedDescription, [NSNull null]]);
在RN中调用返回方法
_handleNavigationBackRequest() {
var RNBridge = NativeModules.RNB
RNBridge.back();
在RN中获取已填写的返款信息
_applySettlementRequest() {
var status = this.props["status"];
// status参数说明
if (status === 0) {
var RNBridge = NativeModules.RNB
var orderid = this.props["orderid"].toString();
RNBridge.applySettlement(orderid,(error, events) =& {
if (error) {
console.error(error);
.money = (.money/100).toString();
this.setState({events: events});
在模拟器中 command+D 调出RN的菜单,点击Debug JS Remotely。
在需要调试的代码前面加debugger,例如
_onButtonPress() {
var orderInfo = this.;
orderInfo.money = Number(orderInfo.money*100);
if(isNaN(orderInfo.money)){
AlertIOS.alert(
'请输入正确的返款金额',
简陋,够用?(°?‵?′??)
5.上线以及热更新
上线的时候需要将代码中的jsCodeLocation修改一下
//let jsCodeLocation = URL(string: "http://localhost:8081/index.ios.bundle?platform=ios")
let jsCodeLocation = Bundle.main.url(forResource: "main", withExtension: "jsbundle")
这个main.jsbundle是需要手动生成的,生成方法如下:
1.在React Native项目根目录下运行 npm start
2.使用curl命令生成 main.jsbundle
curl http://localhost:8081/index.ios.bundle -o main.jsbundle
这样进入RN页面的时候,顶上就不再有提示信息了。如果提示找不到这个main.jsbundle文件,记得把main.jsbundle拖到iOS工程中引用一下。
打开main.jsbundle文件,你会发现里面包含了你所写的所有js文件内容。所以其实你写的RN逻辑全在这里面。那么RN的热更新就很好理解了,更新这个文件就好了。不管你自己实现还是选择什么第三方热更新方案,都是在各种花式更新这个main.jsbundle文件而已。
6.一些补充和问题(碎碎念)
之前只讲了push跳转页面,modal喃?举例一发
&View style={{marginTop: 22}}&
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() =& {alert("closed")}}
&View style={{marginTop: 22}}&
&Text&Hello World!&/Text&
&TouchableHighlight onPress={() =& {
this.setModalVisible(!this.state.modalVisible)
&Text&Hide Modal&/Text&
&/TouchableHighlight&
&TouchableHighlight onPress={() =& {this.setModalVisible(true)}}&
&Text&Show Modal&/Text&
&/TouchableHighlight&
另外补充一个小问题,如果npm start命令不好使的时候,尝试一下react-native start
还有一个遗留问题,返回native页面的时候我是调用的native方法返回的,难道RN自己不能返回吗,我其实是尝试这样的,也觉得这很理所当然。打印native的navi.viewControllers,最后的UIViewController就是RN页面,NavigatorIOS的pop方法调用了竟然没反应,难道是我姿势不对?
(lldb) po navi.viewControllers
&__NSArrayI 0x&(
&MECRM.MainOrderViewController: 0x7f82a1226ac0&,
&MECRM.OrderDetailViewController: 0x7f829f54e2c0&,
&UIViewController: 0x7f82a1004ed0&
RN官方提供了NavigatorIOS和Navigator,使用方法大同小异,总感觉带个iOS更贴近原生。不过都说Navigator更cool。
iOS熟练工/Web小马仔今天看啥 热点:
iOS 实现一个类似电商购物车界面示例,ios电商购物车示例
iOS 实现一个类似电商购物车界面示例
先看界面效果图:
主要实现了商品的展示,并且可以对商品进行多选操作,以及改变商品的购买数量。与此同时,计算出,选中的总价格。
做此类型项目:要注意的:视图与数据要分离开来。视图的展现来源是数据模型层。所以我做的操作就是改变数据层的内容,在根据数据内容,去更新视图界面。
已下是具体实现思路与代码:
1. 实现步骤
在AppDelegate.m中包含ViewController.h头文件,创建ViewController对象(vc),接着创建一个UINavigationController对象(nVC)将vc设置为自己的根视图,最后设置self.window.rootViewController为nVC。在ViewController.m中创建一个全局的可变数组,并往里面添加表格需要的数据字典对象。创建一个GoodsInfoModel 类,继承于NSObject 类,用于做数据模型创建一个MyCustomCell 类 ,继承于UITableViewCell,自定义单元格类在MyCustomCell.m 类中,实现单元格的布局在 ViewController.m 创建表格视图,并且创建表格尾部视图MyCustomCell 类中定义协议,实现代理,完成加、减的运算。在 ViewController.m 实现全选运算。
2. 代码实现
2.1 完成界面的导航栏创建
在AppDelegate.m中包含ViewController.h头文件,创建ViewController对象(vc),接着创建一个UINavigationController对象(nVC)将vc设置为自己的根视图,最后设置self.window.rootViewController为nVC。
2.1.1 代码
在AppDelegate.m的 - (BOOL)application:(UIApplication
)application didFinishLaunchingWithOptions:(NSDictionary )launchOptions方法中实现以下代码(记得包含#import &ViewController.h&):
&//创建窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
//创建一个导航控制器,成为根视图
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:[ViewController new]];
self.window.rootViewController =
//显示窗口
[self.window makeKeyAndVisible];
在 ViewController.m 的 viewDidLoad 中去设置,导航栏标题
& & self.title = @&购物车&;
& & //设置标题的属性样式等
& & [self.navigationController.navigationBar& & setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor& blackColor],NSFontAttributeName:[UIFont systemFontOfSize:23.0f]}];
2.2 创建一个模型类用于存放数据模型
创建一个GoodsInfoModel 类 ,继承于 NSObject
实现代码如下: GoodsInfoModel.h 中
@interface GoodsInfoModel : NSObject
@property(strong,nonatomic)NSString *imageN//商品图片
@property(strong,nonatomic)NSString *goodsT//商品标题
@property(strong,nonatomic)NSString *goodsP//商品单价
@property(assign,nonatomic)BOOL selectS//是否选中状态
@property(assign,nonatomic)int goodsN//商品个数
-(instancetype)initWithDict:(NSDictionary *)
GoodsInfoModel.m 中
-(instancetype)initWithDict:(NSDictionary *)dict
if (self = [super init])
& & self.imageName = dict[@&imageName&];
& & self.goodsTitle = dict[@&goodsTitle&];
& & self.goodsPrice = dict[@&goodsPrice&];
& & self.goodsNum = [dict[@&goodsNum&]intValue];
& & self.selectState = [dict[@&selectState&]boolValue];
2.3 创建设置表格数据的数据
在ViewController.m中创建一个全局的可变数组,并往里面添加表格需要的数据字典对象。
2.3.1 代码
在ViewController.m的- (void)viewDidLoad中实现以下代码(先在ViewController.m中声明infoArr对象)。代码如下
@interface ViewController ()&UITableViewDataSource,UITableViewDelegate,MyCustomCellDelegate&
& & UITableView *_MyTableV
& & float allP
& & NSMutableArray *infoA
@property(strong,nonatomic)UIButton *allSelectB
@property(strong,nonatomic)UILabel *allPriceL
---------------------------------------------------------------
& & //初始化数据
allPrice = 0.0;
infoArr = [[NSMutableArray alloc]init];
&*& 初始化一个数组,数组里面放字典。字典里面放的是单元格需要展示的数据
for (int i = 0; i&7; i++)
& & NSMutableDictionary *infoDict = [[NSMutableDictionary alloc]init];
& & [infoDict setValue:@&img6.png& forKey:@&imageName&];
& & [infoDict setValue:@&这是商品标题& forKey:@&goodsTitle&];
& & [infoDict setValue:@&2000& forKey:@&goodsPrice&];
& & [infoDict setValue:[NSNumber numberWithBool:NO] forKey:@&selectState&];
& & [infoDict setValue:[NSNumber numberWithInt:1] forKey:@&goodsNum&];
& & //封装数据模型
& & GoodsInfoModel *goodsModel = [[GoodsInfoModel alloc]initWithDict:infoDict];
& & //将数据模型放入数组中
& & [infoArr addObject:goodsModel];
2.4 创建表格视图
代码如下: /* 创建表格,并设置代理 /
_MyTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
_MyTableView.dataSource =
_MyTableView.delegate =
//给表格添加一个尾部视图
_MyTableView.tableFooterView = [self creatFootView];
[self.view addSubview:_MyTableView];
2.5 创建尾部视图
代码如下:
/* * 创建表格尾部视图 * * @return 返回一个UIView 对象视图,作为表格尾部视图
-(UIView *)creatFootView{
UIView *footView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)];
//添加一个全选文本框标签
UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(self.view.frame.size.width - 150, 10, 50, 30)];
lab.text = @&全选&;
[footView addSubview:lab];
//添加全选图片按钮
_allSelectBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_allSelectBtn.frame = CGRectMake(self.view.frame.size.width- 100, 10, 30, 30);
[_allSelectBtn setImage:[UIImage imageNamed:@&复选框-未选中&] forState:UIControlStateNormal];
[_allSelectBtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[footView addSubview:_allSelectBtn];
//添加小结文本框
UILabel *lab2 = [[UILabel alloc]initWithFrame:CGRectMake(self.view.frame.size.width - 150, 40, 60, 30)];
lab2.textColor = [UIColor redColor];
lab2.text = @&小结:&;
[footView addSubview:lab2];
//添加一个总价格文本框,用于显示总价
_allPriceLab = [[UILabel alloc]initWithFrame:CGRectMake(self.view.frame.size.width - 100, 40, 100, 30)];
_allPriceLab.textColor = [UIColor redColor];
_allPriceLab.text = @&0.0&;
[footView addSubview:_allPriceLab];
//添加一个结算按钮
UIButton *settlementBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[settlementBtn setTitle:@&去结算& forState:UIControlStateNormal];
[settlementBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
settlementBtn.frame = CGRectMake(10, 80, self.view.frame.size.width - 20, 30);
settlementBtn.backgroundColor = [UIColor blueColor];
[footView addSubview:settlementBtn];
return footV
2.6 创建自定义cell类,并实现初始化方法
创建一个类名叫MyCustomCell继承UITableViewCell,在MyCustomCell.m中实现重写的初始化方法。
2.6.1 代码:
MyCustomCell.h :
#import &UIKit/UIKit.h&
#import &GoodsInfoModel.h&
//添加代理,用于按钮加减的实现
@protocol MyCustomCellDelegate &NSObject&
-(void)btnClick:(UITableViewCell *)cell andFlag:(int)
@interface MyCustomCell : UITableViewCell
@property(strong,nonatomic)UIImageView *goodsImgV;//商品图片
@property(strong,nonatomic)UILabel *goodsTitleL//商品标题
@property(strong,nonatomic)UILabel *priceTitleL//价格标签
@property(strong,nonatomic)UILabel *priceL//具体价格
@property(strong,nonatomic)UILabel *goodsNumL//购买数量标签
@property(strong,nonatomic)UILabel *numCountL//购买商品的数量
@property(strong,nonatomic)UIButton *addB//添加商品数量
@property(strong,nonatomic)UIButton *deleteB//删除商品数量
@property(strong,nonatomic)UIButton *isSelectB//是否选中按钮
@property(strong,nonatomic)UIImageView *isSelectI//是否选中图片
@property(assign,nonatomic)BOOL selectS//选中状态
@property(assign,nonatomic)id&MyCustomCellDelegate&
//赋值
-(void)addTheValue:(GoodsInfoModel *)goodsM
MyCustomCell.m :先写一个宏定义宽度。#define WIDTH ([UIScreen mainScreen].bounds.size.width)
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])
& & //布局界面
& & UIView * bgView = [[UIView alloc]initWithFrame:CGRectMake(5, 5, WIDTH-10, 95)];
& & bgView.backgroundColor = [UIColor whiteColor];
& & //添加商品图片
& & _goodsImgV = [[UIImageView alloc]initWithFrame:CGRectMake(5, 10, 80, 80)];
& & _goodsImgV.backgroundColor = [UIColor greenColor];
& & [bgView addSubview:_goodsImgV];
& & //添加商品标题
& & _goodsTitleLab = [[UILabel alloc]initWithFrame:CGRectMake(90, 5, 200, 30)];
& & _goodsTitleLab.text = @&afadsfa fa&;
& & _goodsTitleLab.backgroundColor = [UIColor clearColor];
& & [bgView addSubview:_goodsTitleLab];
& & //促销价
& & _priceTitleLab = [[UILabel alloc]initWithFrame:CGRectMake(90, 35, 70, 30)];
& & _priceTitleLab.text = @&促销价:&;
& & _priceTitleLab.backgroundColor = [UIColor clearColor];
& & [bgView addSubview:_priceTitleLab];
& & //商品价格
& & _priceLab = [[UILabel alloc]initWithFrame:CGRectMake(160, 35, 100, 30)];
& & _priceLab.text = @&1990&;
& & _priceLab.textColor = [UIColor redColor];
& & [bgView addSubview:_priceLab];
& & //购买数量
& & _goodsNumLab = [[UILabel alloc]initWithFrame:CGRectMake(90, 65, 90, 30)];
& & _goodsNumLab.text = @&购买数量:&;
& & [bgView addSubview:_goodsNumLab];
& & //减按钮
& & _deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
& & _deleteBtn.frame = CGRectMake(180, 65, 30, 30);
& & [_deleteBtn setImage:[UIImage imageNamed:@&按钮-.png&] forState:UIControlStateNormal];
& & [_deleteBtn addTarget:self action:@selector(deleteBtnAction:) forControlEvents:UIControlEventTouchUpInside];
& & _deleteBtn.tag = 11;
& & [bgView addSubview:_deleteBtn];
& & //购买商品的数量
& & _numCountLab = [[UILabel alloc]initWithFrame:CGRectMake(210, 65, 50, 30)];
& & _numCountLab.textAlignment = NSTextAlignmentC
& & [bgView addSubview:_numCountLab];
& & //加按钮
& & _addBtn = [UIButton buttonWithType:UIButtonTypeCustom];
& & _addBtn.frame = CGRectMake(260, 65, 30, 30);
& & [_addBtn setImage:[UIImage imageNamed:@&按钮+.png&] forState:UIControlStateNormal];
& & [_addBtn addTarget:self action:@selector(addBtnAction:) forControlEvents:UIControlEventTouchUpInside];
& & _addBtn.tag = 12;
& & [bgView addSubview:_addBtn];
& & //是否选中图片
& & _isSelectImg = [[UIImageView alloc]initWithFrame:CGRectMake(WIDTH - 50, 10, 30, 30)];
& & [bgView addSubview:_isSelectImg];
& & [self addSubview:bgView];
&*& 给单元格赋值
&*& @param goodsModel 里面存放各个控件需要的数值
-(void)addTheValue:(GoodsInfoModel *)goodsModel
_goodsImgV.image = [UIImage imageNamed:goodsModel.imageName];
_goodsTitleLab.text = goodsModel.goodsT
_priceLab.text = goodsModel.goodsP
_numCountLab.text = [NSString stringWithFormat:@&%d&,goodsModel.goodsNum];
if (goodsModel.selectState)
& & _selectState = YES;
& & _isSelectImg.image = [UIImage imageNamed:@&复选框-选中&];
& & _selectState = NO;
& & _isSelectImg.image = [UIImage imageNamed:@&复选框-未选中&];
&*& 点击减按钮实现数量的减少
&*& @param sender 减按钮
-(void)deleteBtnAction:(UIButton *)sender
//判断是否选中,选中才能点击
if (_selectState == YES)
& & //调用代理
& & [self.delegate btnClick:self andFlag:(int)sender.tag];
&*& 点击加按钮实现数量的增加
&*& @param sender 加按钮
-(void)addBtnAction:(UIButton *)sender
//判断是否选中,选中才能点击
if (_selectState == YES)
& & //调用代理
& & [self.delegate btnClick:self andFlag:(int)sender.tag];
2.7 实现表格的代理方法
//返回单元格个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:& (NSInteger)section
& & return infoArr.
//定制单元格内容
- (UITableViewCell *)tableView:(UITableView *)tableView & & cellForRowAtIndexPath:(NSIndexPath *)indexPath
& & static NSString *identify =& @&indentify&;
&& & MyCustomCell *cell = [tableView& & dequeueReusableCellWithIdentifier:identify];
& & if (!cell)
& & & & cell = [[MyCustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identify];
&& & cell.delegate =
& & //调用方法,给单元格赋值
& & [cell addTheValue:infoArr[indexPath.row]];
//返回单元格的高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
& & return 120;
//单元格选中事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
&*& 判断当期是否为选中状态,如果选中状态点击则更改成未选中,如果未选中点击则更改成选中状态
GoodsInfoModel *model = infoArr[indexPath.row];
if (model.selectState)
& & model.selectState = NO;
& & model.selectState = YES;
//刷新整个表格
//& & [_MyTableView reloadData];
//刷新当前行
[_MyTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self totalPrice];
2.8 实现单元格加、减按钮代理
先要再ViewController.m 中导入MyCustomCellDelegate 协议
@interface ViewController ()&UITableViewDataSource,UITableViewDelegate,MyCustomCellDelegate&
然后实现代码如下:
#pragma mark -- 实现加减按钮点击代理事件
*& 实现加减按钮点击代理事件
*& @param cell 当前单元格
*& @param flag 按钮标识,11 为减按钮,12为加按钮
-(void)btnClick:(UITableViewCell *)cell andFlag:(int)flag
&NSIndexPath *index = [_MyTableView indexPathForCell:cell];
switch (flag) {
& & case 11:
& & & & //做减法
& & & & //先获取到当期行数据源内容,改变数据源内容,刷新表格
& & & & GoodsInfoModel *model = infoArr[index.row];
& & & & if (model.goodsNum & 1)
& & & & & & model.goodsNum --;
& & case 12:
& & & & //做加法
& & & & GoodsInfoModel *model = infoArr[index.row];
& & & & model.goodsNum ++;
& & default:
//刷新表格
[_MyTableView reloadData];
//计算总价
[self totalPrice];
2.8 全选方法的实现
*& 全选按钮事件
*& @param sender 全选按钮
-(void)selectBtnClick:(UIButton *)sender
& & //判断是否选中,是改成否,否改成是,改变图片状态
& & sender.tag = !sender.
& & if (sender.tag)
& & & & [sender setImage:[UIImage imageNamed:@&复选框-选中.png&] & forState:UIControlStateNormal];
& & [sender setImage:[UIImage imageNamed:@&复选框-未选中.png&] forState:UIControlStateNormal];
//改变单元格选中状态
for (int i=0; i&infoArr. i++)
& & GoodsInfoModel *model = [infoArr objectAtIndex:i];
& & model.selectState = sender.
//计算价格
[self totalPrice];
//刷新表格
[_MyTableView reloadData];
2.9 计算总价格
#pragma mark -- 计算价格
-(void)totalPrice
& & //遍历整个数据源,然后判断如果是选中的商品,就计算价格(单价 * 商品数量)
& & for ( int i =0; i&infoArr. i++)
& & GoodsInfoModel *model = [infoArr objectAtIndex:i];
& & if (model.selectState)
& & & & allPrice = allPrice + model.goodsNum *[model.goodsPrice intValue];
//给总价文本赋值
_allPriceLab.text = [NSString stringWithFormat:@&%.2f&,allPrice];
NSLog(@&%f&,allPrice);
//每次算完要重置为0,因为每次的都是全部循环算一遍
allPrice = 0.0;
短时间手写:代码比较粗糙,没有完全整理;
&请点击:Demo示例下载& &或:http://download.csdn.net/detail/ljh4357
相关搜索:
相关阅读:
相关频道:
Android教程最近更新}

我要回帖

更多关于 网页嵌入实时视频监控 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信