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函数?

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值