我使用的是C語(yǔ)言編寫(xiě)的庫(kù)libxlsxwriter創(chuàng)建的excel表格,用法在libxlsxwriter英文文檔
,導(dǎo)出/預(yù)覽/分享excel,使用的是原生的UIDocumentInteractionController實(shí)現(xiàn)的。
在項(xiàng)目中的使用步驟如下
步驟一:使用cocoapods下載libxlsxwriter至項(xiàng)目,我的項(xiàng)目文件名為feiyangApp
1-1: 打開(kāi)Terminal終端,輸入
cd /Users/zhangbin/Desktop/feiyang/feiyangApp進(jìn)入項(xiàng)目feiyangApp
1-2:終端輸入vim Podfile,進(jìn)入該文件
1-3:進(jìn)入Podfile文件后,輸入i,進(jìn)入編輯模式。(出現(xiàn)-- INSERT --就說(shuō)明進(jìn)入編輯模式)
1-4 : 在該文件中輸入pod 'libxlsxwriter'
1-5 : 先按esc,再輸入:wq,保存剛才的編輯操作再退出。
1-6 : 終端中輸入pod install --verbose --no-repo-update,安裝libxlsxwriter庫(kù),且不更新已安裝的其他庫(kù)。
image.png
image.png
在項(xiàng)目中查看是否安裝成功
image.png
步驟二:oc項(xiàng)目中使用libxlsxwriter
2.1導(dǎo)入#import <xlsxwriter/xlsxwriter.h>
2.2 表格數(shù)據(jù)源如下
{
"status" : 200,
"msg" : "OK",
"data" : [
{
"accountNo" : "16160308190000014623",
"paymentTime" : 1590818573000,
"allInPayOrderNo" : "1266608536524165120",
"discountMoney" : 0,
"title" : "炸雞原料",
"orderNo" : "1590817979569664160",
"price" : 1,
"num" : "1",
"benefitCategoryName" : "其他",
"companyName" : "山東xxxxxx科技有限公司",
"benefitCategoryCode" : "W101103105101",
"orderInfo" : "{"商品名稱(chēng)":"炸雞原料","商品分類(lèi)代碼":"W101103105101","商品數(shù)量":"1","商品單價(jià)":1.00,"商品分類(lèi)名稱(chēng)":"其他"}",
"originalPayment" : 1,
"payment" : 1,
"couponName" : null
},
{
"accountNo" : "16160308190000014623",
"paymentTime" : 1591344525000,
"allInPayOrderNo" : "1268816331247988736",
"discountMoney" : 10,
"title" : "炸雞原料",
"orderNo" : "1591343029512428230",
"price" : 1,
"num" : "109",
"benefitCategoryName" : "其他",
"companyName" : "山東xxxxxx科技有限公司",
"benefitCategoryCode" : "W101103105101",
"orderInfo" : "{"商品名稱(chēng)":"炸雞原料","商品分類(lèi)代碼":"W101103105101","商品數(shù)量":"109","商品單價(jià)":1.00,"商品分類(lèi)名稱(chēng)":"其他"}",
"originalPayment" : 10.02,
"payment" : 0.02,
"couponName" : null
},
{
"accountNo" : "16160308190000014623",
"paymentTime" : 1591348105000,
"allInPayOrderNo" : "1268831237196234752",
"discountMoney" : 20,
"title" : "炸雞原料",
"orderNo" : "1591347802389069549",
"price" : 1,
"num" : "104",
"benefitCategoryName" : "其他",
"companyName" : "山東xxxxxx科技有限公司",
"benefitCategoryCode" : "W101103105101",
"orderInfo" : "{"商品名稱(chēng)":"炸雞原料","商品分類(lèi)代碼":"W101103105101","商品數(shù)量":"104","商品單價(jià)":1.00,"商品分類(lèi)名稱(chēng)":"其他"}",
"originalPayment" : 20.02,
"payment" : 0.02,
"couponName" : null
}
]
}
2.3 主要代碼如下
#import "ZB_AccountStatementController.h"
#import "ZB_AccountModel.h"
#import <xlsxwriter/xlsxwriter.h>
@interface ZB_AccountStatementController ()<UIDocumentInteractionControllerDelegate>
@property (nonatomic,strong) NSMutableArray<ZB_AccountModel *> *accountDataArray;
@property (nonatomic,strong) UIButton * exportAccountBtn;
@property (nonatomic,strong)UIDocumentInteractionController * document;
@property(nonatomic,assign) NSInteger startYear;
@property(nonatomic,assign) NSInteger startMonth;
@property(nonatomic,assign) NSInteger startDay;
@property(nonatomic,assign) NSInteger endYear;
@property(nonatomic,assign) NSInteger endMonth;
@property(nonatomic,assign) NSInteger endDay;
@end
@implementation ZB_AccountStatementController
-(NSMutableArray *)accountDataArray{
if(!_accountDataArray){
_accountDataArray = [NSMutableArray array];
}
return _accountDataArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self exportAccountUI];
[self netRequest];
}
-(void)exportAccountUI{
int navH = (int)NAV_HEIGHT;
self.exportAccountBtn = [[UIButton alloc]initWithFrame:CGRectMake(0,APP_SCREEN_HEIGHT - navH - BOTTOM_SAFE_AREA - tRealLength(35) ,APP_SCREEN_WIDTH,tRealLength(35))];
self.exportAccountBtn.backgroundColor = [UIColor whiteColor];
[self.exportAccountBtn setTitle:@"導(dǎo)出當(dāng)前對(duì)賬單" forState:UIControlStateNormal];
[self.exportAccountBtn setImage:[UIImage imageNamed:@"benefit_export.png"] forState:UIControlStateNormal];
[self.exportAccountBtn setTitleColor:[UIColor colorWithHexString:@"#a61b29"] forState:UIControlStateNormal];
self.exportAccountBtn.titleLabel.font = [UIFont systemFontOfSize:tRealFontSize(14)];
[self.exportAccountBtn addTarget:self action:@selector(exportAccountClick:) forControlEvents:UIControlEventTouchUpInside];
self.exportAccountBtn.hidden = YES;
[self.view addSubview:self.exportAccountBtn];
}
-(void)netRequest{
// ....
// 數(shù)據(jù)請(qǐng)求,拿到數(shù)據(jù)源
// 指定路徑下創(chuàng)建excel
[self creationExcel];
}
// 創(chuàng)建excel
-(void)creationExcel{
// 獲取cache路徑
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *xlsxName = [NSString stringWithFormat:@"%ld年%ld月%ld日-%ld年%ld月%ld日對(duì)賬單.xlsx",self.startYear,self.startMonth,self.startDay,self.endYear,self.endMonth,self.endDay];
// 拼接 cache路徑 + 名為xlsxName的文件 注意:該路徑下的文件名一定要和后續(xù)導(dǎo)出的文件名保持一致,否則后續(xù)執(zhí)行導(dǎo)出操作時(shí),讀取不到該文件
NSString *filename = [documentDirectory stringByAppendingPathComponent:xlsxName];
// 創(chuàng)建新xlsx文件,路徑需要轉(zhuǎn)成c字符串
lxw_workbook *workbook = workbook_new([filename UTF8String]);
// 創(chuàng)建sheet
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
// 格式1
lxw_format *titleformat = workbook_add_format(workbook);
// 加粗
format_set_bold(titleformat);
// 字體尺寸
format_set_font_size(titleformat, 20);
// 內(nèi)容垂直居中
format_set_align(titleformat, LXW_ALIGN_VERTICAL_CENTER);
// 內(nèi)容水平居中
format_set_align(titleformat, LXW_ALIGN_CENTER);
// 合并單元格。0行0列到0行8列合并為一行,并設(shè)定內(nèi)容為"(山東)文旅惠民消費(fèi)券《核銷(xiāo)結(jié)算表》"
worksheet_merge_range(worksheet, 0, 0,0, 8, [@"(山東)文旅惠民消費(fèi)券《核銷(xiāo)結(jié)算表》" cStringUsingEncoding:NSUTF8StringEncoding], titleformat);
// 格式2
lxw_format *columnTitleformat = workbook_add_format(workbook);
// 內(nèi)容垂直居中
format_set_align(columnTitleformat, LXW_ALIGN_VERTICAL_CENTER);
// 內(nèi)容水平居中
format_set_align(columnTitleformat, LXW_ALIGN_CENTER);
// 將"統(tǒng)計(jì)周期:" 的總價(jià)寫(xiě)入到1行5列
worksheet_write_string(worksheet, 1, 5, [@"統(tǒng)計(jì)周期:" UTF8String], columnTitleformat);
// 將"填報(bào)日期:" 的總價(jià)寫(xiě)入到1行7列
worksheet_write_string(worksheet, 1, 7, [@"填報(bào)日期:" UTF8String], columnTitleformat);
// 第1行的高度為20,并將格式2應(yīng)用到該行上。注意 行的高度和列表的寬度的值單位不一樣,此50非彼50
worksheet_set_row(worksheet, 1, 30, columnTitleformat);
// 第0列到第8列的寬度為30。注意 此30非彼30
worksheet_set_column(worksheet, 0, 8, 30.0, NULL);
// 第2行的高度為30,并將格式2應(yīng)用到該行上。注意 行的高度和列表的寬度的值單位不一樣,此30非彼30
worksheet_set_row(worksheet, 2, 30, columnTitleformat);
// 將"序號(hào)"寫(xiě)入到2行0列
worksheet_write_string(worksheet, 2, 0, [@"序號(hào)" UTF8String], columnTitleformat);
// 將"企業(yè)名稱(chēng)"寫(xiě)入到2行1列
worksheet_write_string(worksheet, 2, 1, [@"企業(yè)名稱(chēng)" UTF8String], columnTitleformat);
// 將"商家賬號(hào)"寫(xiě)入到2行2列
worksheet_write_string(worksheet, 2, 2, [@"商家賬號(hào)" UTF8String], columnTitleformat);
// 將"消費(fèi)日期"寫(xiě)入到2行3列
worksheet_write_string(worksheet, 2, 3, [@"消費(fèi)日期" UTF8String], columnTitleformat);
// 將"銷(xiāo)售訂單號(hào)"寫(xiě)入到2行4列
worksheet_write_string(worksheet, 2, 4, [@"銷(xiāo)售訂單號(hào)" UTF8String], columnTitleformat);
// 將"銷(xiāo)售金額"寫(xiě)入到2行5列
worksheet_write_string(worksheet, 2, 5, [@"銷(xiāo)售金額" UTF8String], columnTitleformat);
// 將"通聯(lián)訂單號(hào)"寫(xiě)入到2行6列
worksheet_write_string(worksheet, 2, 6, [@"通聯(lián)訂單號(hào)" UTF8String], columnTitleformat);
// 將"優(yōu)惠(券)"寫(xiě)入到2行7列
worksheet_write_string(worksheet, 2, 7, [@"優(yōu)惠(券)" UTF8String], columnTitleformat);
// 將"實(shí)付金額"寫(xiě)入到2行8列
worksheet_write_string(worksheet, 2, 8, [@"實(shí)付金額" UTF8String], columnTitleformat);
int rowA = 3 + (int)self.accountDataArray.count;
// 合并單元格。rowA行0列 到 rowA行5列合并為一行,并設(shè)定內(nèi)容為 "合計(jì):"
worksheet_merge_range(worksheet, rowA, 0 ,rowA, 5, [@"合計(jì):" cStringUsingEncoding:NSUTF8StringEncoding], columnTitleformat);
// 第rowA行的高度為50。注意 行的高度和列表的寬度的值單位不一樣,此50非彼50
worksheet_set_row(worksheet, rowA, 50, columnTitleformat);
float discountPrice = 0.00;
float realPrice = 0.00;
// 統(tǒng)計(jì) 優(yōu)惠(券)所在列的總價(jià) 和 實(shí)付金額 所在列的總價(jià)
for (int i = 0; i < self.accountDataArray.count; i++) {
ZB_AccountModel *model = self.accountDataArray[i];
discountPrice = discountPrice + [model.discountMoney floatValue];
realPrice = realPrice + [model.payment floatValue];
}
// 將優(yōu)惠(券)所在列的總價(jià)寫(xiě)入到rowA行7列
worksheet_write_string(worksheet, rowA, 7, [[NSString stringWithFormat:@"%.2lf",discountPrice] UTF8String], columnTitleformat);
// 將實(shí)付金額 所在列的總價(jià)寫(xiě)入到rowA行8列
worksheet_write_string(worksheet, rowA, 8, [[NSString stringWithFormat:@"%.2lf",realPrice] UTF8String], columnTitleformat);
int rowB = 4 + (int)self.accountDataArray.count;
// 合并單元格。rowB行0列 到 rowB行1列合并為一行,并設(shè)定內(nèi)容為 "負(fù)責(zé)人:"
worksheet_merge_range(worksheet, rowB, 0 ,rowB, 1, [@"負(fù)責(zé)人:" cStringUsingEncoding:NSUTF8StringEncoding], columnTitleformat);
// 合并單元格。rowB行3列 到 rowB行4列合并為一行,并設(shè)定內(nèi)容為 "填表人:"
worksheet_merge_range(worksheet, rowB, 3 ,rowB, 4, [@"填表人:" cStringUsingEncoding:NSUTF8StringEncoding], columnTitleformat);
// 合并單元格。rowB行6列 到 rowB行7列合并為一行,并設(shè)定內(nèi)容為 "單位:(蓋章)"
worksheet_merge_range(worksheet, rowB, 6 ,rowB, 7, [@"單位:(蓋章)" cStringUsingEncoding:NSUTF8StringEncoding], columnTitleformat);
// 第rowB行的高度為50,并將格式2應(yīng)用到該行上。注意 行的高度和列表的寬度的值單位不一樣,此50非彼50
worksheet_set_row(worksheet, rowB, 50, columnTitleformat);
// 格式3
lxw_format *markformat = workbook_add_format(workbook);
// 內(nèi)容垂直居中
format_set_align(markformat, LXW_ALIGN_VERTICAL_CENTER);
// 內(nèi)容水平居中
format_set_align(markformat, LXW_ALIGN_CENTER);
// 字體尺寸
format_set_font_size(markformat, 17);
// 字體顏色
format_set_font_color(markformat,0xFF0000);
int rowC = 5 + (int)self.accountDataArray.count;
// 合并單元格。rowC行0列 到 rowB行8列合并為一行,并設(shè)定內(nèi)容為 "備注1、使用文化和旅游惠民消費(fèi)券的訂單,以通聯(lián)訂單號(hào)為唯一標(biāo)識(shí)逐筆填寫(xiě)。"
worksheet_merge_range(worksheet, rowC, 0 ,rowC, 8, [@"備注1、使用文化和旅游惠民消費(fèi)券的訂單,以通聯(lián)訂單號(hào)為唯一標(biāo)識(shí)逐筆填寫(xiě)。" cStringUsingEncoding:NSUTF8StringEncoding], markformat);
// 第rowC行的高度為50,并將格式3應(yīng)用到該行上。注意 行的高度和列表的寬度的值單位不一樣,此30非彼30
worksheet_set_row(worksheet, rowC, 30, markformat);
// 遍歷數(shù)據(jù)源,將表格數(shù)據(jù)寫(xiě)入到某行某列中
for (int i = 0; i < self.accountDataArray.count; i++) {
ZB_AccountModel *model = self.accountDataArray[i];
NSString *calTime = [FYTimeManager timeWithDataTime:model.paymentTime/1000];
worksheet_set_row(worksheet, 3+i, 30, columnTitleformat);
worksheet_write_string(worksheet, 3+i, 0, [[NSString stringWithFormat:@"%d",i+1] UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 1, [model.companyName UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 2, [model.accountNo UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 3, [calTime UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 4, [model.orderNo UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 5, [model.price UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 6, [model.allInPayOrderNo UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 7, [model.discountMoney UTF8String], columnTitleformat);
worksheet_write_string(worksheet, 3+i, 8, [model.payment UTF8String], columnTitleformat);
}
//保存
workbook_close(workbook);
}
// 導(dǎo)出按鈕點(diǎn)擊
-(void)exportAccountClick:(UIButton *)btn{
// 獲取cache路徑
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSLog(@"documentDirectory為%@",documentDirectory);
NSString *xlsxName = [NSString stringWithFormat:@"%ld年%ld月%ld日-%ld年%ld月%ld日對(duì)賬單.xlsx",self.startYear,self.startMonth,self.startDay,self.endYear,self.endMonth,self.endDay];
// 拼接 cache路徑 + 名為xlsxName的文件。注意:注意filename一定要和當(dāng)初創(chuàng)建時(shí)的文件名保持一致,否則讀取不到該文件
NSString *filename = [documentDirectory stringByAppendingPathComponent:xlsxName];
// 初始化并讀取路徑為filename的文件
self.document = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filename]];
self.document.delegate = self;
// 以present的方式展示該文件所支持的第三方App列表
[self.document presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];
}
#pragma mark - documentDelegate
-(UIViewController*)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController*)controller{
return self;
}
- (UIView*)documentInteractionControllerViewForPreview:(UIDocumentInteractionController*)controller {
return self.view;
}
- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController*)controller {
return self.view.frame;
}
//點(diǎn)擊預(yù)覽窗口的“Done”(完成)按鈕時(shí)調(diào)用
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController*)controller {
}
// 文件分享面板彈出的時(shí)候調(diào)用
- (void)documentInteractionControllerWillPresentOpenInMenu:(UIDocumentInteractionController*)controller{
NSLog(@"WillPresentOpenInMenu");
}
// 當(dāng)選擇一個(gè)文件分享App的時(shí)候調(diào)用
- (void)documentInteractionController:(UIDocumentInteractionController*)controller willBeginSendingToApplication:(nullable NSString*)application{
NSLog(@"begin send : %@", application);
}
// 彈框消失的時(shí)候走的方法
-(void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController*)controller{
NSLog(@"dissMiss");
}
@end
效果
-
使用的UITableview做的效果
image.png -
導(dǎo)出按鈕點(diǎn)擊,彈出可以支持該文件的三方App
image.png -
excel導(dǎo)出發(fā)送到App中
image.png





