栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

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

-(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;

    

    //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()
{
    
    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函数?
答案下次公布,有兴趣的,可以留言回答!呵呵呵!!!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/233122.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号