当前位置: 首页 > news >正文

android 混合编程,用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(二B)...

CalendarDelegate协议中索引、月份映射关系以及UITableView中CalendarView的定位问题:

千言万语,不如再来一张图来的清晰

AAffA0nNPuCLAAAAAElFTkSuQmCC

-(SDate) mapIndexToYearMonth : (int) index

{

SDate ret;

//调用c函数,将索引号映射成年月,用于UITableView创建calendarView时现实月历标题

date_map_index_to_year_month(&ret, _startYear, index);

return ret;

}

//调用mapIndexToYearMonth:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

static NSString* calendarID = @"calendarID";

float width = self.tableView.frame.size.width;

//从行索引号映射到年月

SDate date = [self mapIndexToYearMonth:(int)indexPath.row];

//获取重用的cell

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:calendarID ];

//如果为null,说明不存在,创建该cell

if(cell == nil)

{

//可以在此断点,查看一下具体生成了多少个calendarView(我这里生成了3个)

//说明UITableView可见rect有三个calendarView相交

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:calendarID];

[cell setTag:10];

//手动创建CalendarView

CalendarView* calendarView = [[CalendarView alloc] initWithFrame:CGRectMake(0, 0, width, _calendarHeight)];

//设置CalednarDelegate

calendarView.calendarDelegate = self;

//给定一个tag号,用于重用时获得该view

[calendarView setTag:1000];

[cell.contentView addSubview:calendarView];

}

//通过tag号,获取view

CalendarView* view =(CalendarView*) [cell.contentView viewWithTag:1000];

//设置CalendarView的年月

[view setYearMonth:date.year month:date.month];

//[view setNeedsDisplay];

return cell;

}

-(int) mapYearMonthToIndex:(SDate)date

{

int yearDiff = date.year - _startYear;

int index = yearDiff * 12;

index += date.month;

index -= 1;

return index;

}

//调用mapYearMonthToIndex

-(void) showCalendarAtYearMonth:(SDate)date

{

if(date.year < _startYear date.year > _endYear)

return;

//将年月表示映射成UITableView中的索引号,根据索引计算出要滚动到的目的地

int idx = [self mapYearMonthToIndex:date];

//如上图所示:当idx = calendarViews.length-1时,可能存在超过整个UITableView ContentSize.height情况,此时,UITableView会自动调整contentOffset的值,使其符合定位到最底端,android listview也是如此。

self.tableView.contentOffset = CGPointMake(0.0F, idx * _calendarHeight );

}

1) 从上图以及代码,应该很清楚的了解了映射和定位问题的过程

2) 从上图中,我们也可以了解到UITableView的滚动原理,UITableView的Frame是Clip区域,滚动的内容存放于Content中。

3) UITableView可以说是移动开发中最常用,最重要的一个控件(还有一个是UICollectionView)。有两个主要功能点:滚动(UIScrollView父类)和cell复用。以后有机会我们来从头到尾实现一个带有上述功能的控件。

有了上面的代码,我们就可以初始化CalendarController:

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

//获取当前的年月

SDate date;

date_get_now(&date);

//default有3年

_startYear = date.year-3;

_endYear = date.year;

/*

//当年也支持

_startYear = date.year;

_endYear = date.year;

*/

//touch 计数器

_hitCounter = 0;

float scale = 0.6F;//硬编码,最好由外部设置

//float scale = 0.5F;//硬编码,最好由外部设置

_calendarHeight = self.tableView.frame.size.height * scale;

self.tableView.dataSource = self;

self.tableView.delegate = self;

//default定位显示当前月份

if (self.begDate.year == 0) {

self.begDate = date;

[self showCalendarAtYearMonth:date];

}else{

//当然你也可以设置具体月份重点显示

[self showCalendarAtYearMonth:self.begDate];

}

}

到目前为止,支持CalendarController运行的所有方法都分析完毕,接下来我们要看一下CalendarView相关的实现。(CalendarDelegate还有一些方法没分析,因为这些方法是由CalendarView调用的,由此可见,IOS中的Delegate除了面向接口编程外,还有一个功能就是类之间的通信)

4、 CalendarView:

CalendarView的声明:

//.h文件

@interface CalendarView : UIControl

-(void) setYearMonth : (int) year month : (int) month;

@property (weak, nonatomic) id calendarDelegate;

@end

//.m文件

@interface CalendarView()

{

/*

blf:

引用c结构,所有月历相关操作委托给SCalendar的相关函数

SCalendar 使用栈内存分配

*/

SCalendar _calendar;

//这是一个很重要的变量,具体源码中说明

int _lastMonthDayCount;

//存放月历的日期和星期字符串

NSMutableArray* _dayAndWeekStringArray;

//string绘制时的大小

CGSize _dayStringDrawingSize;

CGSize _weekStringDrawingSize;

}

CalenderView初始化:

- (id)initWithFrame:(CGRect)frame

{

self = [super initWithFrame:frame];

if (self) {

// Initialization code

//年月区块和星期区块的大小按当前view高度的比例来设定

float yearMonthHeight = frame.size.height * 0.095F;

float weekHeight = frame.size.height * 0.089F;

//初始化月历控件,计算出各个区块部分的大小

calendar_init(&_calendar, frame.size, yearMonthHeight, weekHeight);

SDate date = _calendar.date;

//此时date是上个月

date_get_prev_month(&date, 1);

self.backgroundColor = [UIColor clearColor];

//设置日期区块的大小

CGRect rc;

calendar_get_day_cell_rect(&_calendar,&rc,0,0);

CGSize size;

size.height = rc.size.height- 15 ;

size.width = rc.size.width - 15;

//预先分配38个字符串容量的数组

_dayAndWeekStringArray = [NSMutableArray arrayWithCapacity:38];

//0--30表示最多31天日期字符串

for(int i = 0; i < 31; i++)

[_dayAndWeekStringArray addObject: [NSString stringWithFormat:@"%02d",i+1]];

//31--37存储星期字符串

[_dayAndWeekStringArray addObject:@"周日"];

[_dayAndWeekStringArray addObject:@"周一"];

[_dayAndWeekStringArray addObject:@"周二"];

[_dayAndWeekStringArray addObject:@"周三"];

[_dayAndWeekStringArray addObject:@"周四"];

[_dayAndWeekStringArray addObject:@"周五"];

[_dayAndWeekStringArray addObject:@"周六"];

//计算出日期字符串的绘制用尺寸

_dayStringDrawingSize = [self getStringDrawingSize: [_dayAndWeekStringArray objectAtIndex:0]];

//计算出星期字符串的绘制用尺寸

_weekStringDrawingSize = [self getStringDrawingSize: [_dayAndWeekStringArray objectAtIndex:31]];

//UIControl基于控件的事件处理系统,挂接UIControlEventTouchUpInside处理程序

[self addTarget:self action:@selector(handleTouchEvent:forEvent:) forControlEvents:UIControlEventTouchUpInside];

}

return self;

}

//计算要绘制字符串的尺寸的函数如下:

-(CGSize) getStringDrawingSize:(NSString*)str

{

NSAttributedString* attStr = [[NSAttributedString alloc] initWithString:str];

NSRange range = NSMakeRange(0, attStr.length);

NSDictionary* dic = [attStr attributesAtIndex:0 effectiveRange:&range];

CGRect rect = [str boundingRectWithSize:CGSizeMake(0, 0) options:NSStringDrawingUsesLineFragmentOrigin attributes:dic context:nil];

return rect.size;

}

从上面类声明和初始化代码,引出几个问题:

1)为什么继承自UIControl?

2)为什么delegate使用weak?

3)为什么delegate 声明为id?

4)为什么栈分配?

5)为什么同一个CalendarView的类声明需要分别在.h和.m文件中,或者换种说法:这样做有什么好处?

6)为什么初始化只实现了initWithFrame,没有实现initWithCoder,在哪种情况下,还需要override initWithCoder函数?

答案下次公布,有兴趣的,可以留言回答!呵呵呵!!!

相关文章:

  • linux 繁体转简体,Linux下在程序中如何进行繁体中文和简体中文的转换
  • unity android 帧数,Unity技术分享(90)|Dalvik Heap内存过高|版本帧率|MeshRenderer
  • signature=fc7ecc5076a2f28da44d79a455e941f3,ECC Signature Generation Device for RFID Tags
  • android 6.0 数据库权限,简单实现安卓系统6.0的权限问题
  • html什么代码确定x坐标,显示X和Y坐标?
  • 网页设计简历中个人作品html,网页设计师简历自我评价填写样本
  • less在html页面中应用,Less 在浏览器中使用
  • Html网页warning,HtmlUnit中屏蔽warnings
  • html乱码框框,zabbix的web界面中文显示方框出现乱码的解决方法
  • html网页文字代码,网页HTML代码:滚动文字的制作
  • win7计算机上缺少网络协议,win7系统安装ipx协议提示找不到相应的模块的解决方法...
  • html显示十进制字符,非法HTML字符:十进制141
  • 计算机网络社团章程,社团日常规章制度
  • 陕西师范大学计算机组成原理试题及答案,陕西师范大学 计算机组成原理(A)07级...
  • 计算机病毒范畴有,计算机病毒是否属于生物的范畴?
  • JS 中的深拷贝与浅拷贝
  • @angular/forms 源码解析之双向绑定
  • extract-text-webpack-plugin用法
  • HTML中设置input等文本框为不可操作
  • Just for fun——迅速写完快速排序
  • mysql innodb 索引使用指南
  • pdf文件如何在线转换为jpg图片
  • php中curl和soap方式请求服务超时问题
  • SpiderData 2019年2月25日 DApp数据排行榜
  • Vue.js-Day01
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 聊一聊前端的监控
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 温故知新之javascript面向对象
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 在electron中实现跨域请求,无需更改服务器端设置
  • No resource identifier found for attribute,RxJava之zip操作符
  • Nginx实现动静分离
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #14vue3生成表单并跳转到外部地址的方式
  • $jQuery 重写Alert样式方法
  • (day6) 319. 灯泡开关
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (七)c52学习之旅-中断
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (算法)Travel Information Center
  • (转)人的集合论——移山之道
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .NET CLR基本术语
  • .net web项目 调用webService
  • .NET文档生成工具ADB使用图文教程
  • .NET下ASPX编程的几个小问题
  • ??myeclipse+tomcat
  • [ 蓝桥杯Web真题 ]-布局切换
  • [2024最新教程]地表最强AGI:Claude 3注册账号/登录账号/访问方法,小白教程包教包会
  • [javaSE] GUI(事件监听机制)
  • [JavaWeb学习] tomcat简介、安装及项目部署
  • [JS]JavaScript 注释 输入输出语句
  • [JS]变量