blob: c5b57a3206e0a7723f36af5bfd68f2256fc72c30 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import "WXPickerModule.h"
#import "WXConvert.h"
#import "WXUtility.h"
#import "WXComponentManager.h"
#import <UIKit/UIPickerView.h>
#import <UIKit/UIDatePicker.h>
#import <UIKit/UIKit.h>
#define WXPickerHeight 266
#define WXPickerToolBarHeight 44
@interface WXPickerModule() <UIGestureRecognizerDelegate>
@property (nonatomic, strong)NSString * pickerType;
// when resign the picker ,then the focus will be.
@property (nonatomic, strong)UIView * focusToView;
//picker
@property(nonatomic,strong)UIPickerView *picker;
@property(nonatomic,strong)UIView *backgroundView;
@property(nonatomic,strong)UIView *pickerView;
//custom
@property(nonatomic,copy)NSString *title;
@property(nonatomic,strong)UIColor *titleColor;
@property(nonatomic,copy)NSString *cancelTitle;
@property(nonatomic,copy)NSString *confirmTitle;
@property(nonatomic,strong)UIColor *cancelTitleColor;
@property(nonatomic,strong)UIColor *confirmTitleColor;
@property(nonatomic,strong)UIColor *titleBackgroundColor;
@property(nonatomic)CGFloat height;
@property(nonatomic,strong)UIColor *textColor;
@property(nonatomic,strong)UIColor *selectionColor;
//data
@property(nonatomic,copy)NSArray *items;
@property(nonatomic)BOOL isAnimating;
@property(nonatomic)NSInteger index;
@property(nonatomic,copy)WXModuleKeepAliveCallback callback;
//date picker
@property(nonatomic,strong)UIDatePicker *datePicker;
@property(nonatomic)UIDatePickerMode datePickerMode;
@end
@implementation WXPickerModule
@synthesize weexInstance;
WX_EXPORT_METHOD(@selector(pick:callback:))
WX_EXPORT_METHOD(@selector(pickDate:callback:))
WX_EXPORT_METHOD(@selector(pickTime:callback:))
#pragma mark -
#pragma mark Single Picker
-(void)dealloc
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (nil != _backgroundView.superview) {
UIView* backgroundView = _backgroundView;
dispatch_async(dispatch_get_main_queue(), ^{
[backgroundView removeFromSuperview];
});
}
}
-(void)pick:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback
{
if (UIAccessibilityIsVoiceOverRunning()) {
[self handleA11yFocusback:options];
}
_pickerType = @"picker";
NSArray *items = @[];
NSInteger index = 0 ;
if (options[@"items"]) {
items = options[@"items"];
}
if (options[@"index"]) {
index = [WXConvert NSInteger:options[@"index"]];
}
if (options[@"title"]) {
self.title = [WXConvert NSString:options[@"title"]];
}
if (options[@"titleColor"]) {
self.titleColor = [WXConvert UIColor:options[@"titleColor"]];
}
if (options[@"cancelTitle"]) {
self.cancelTitle = [WXConvert NSString:options[@"cancelTitle"]];
}
if (options[@"confirmTitle"]) {
self.confirmTitle = [WXConvert NSString:options[@"confirmTitle"]];
}
if (options[@"cancelTitleColor"]) {
self.cancelTitleColor = [WXConvert UIColor:options[@"cancelTitleColor"]];
}
if (options[@"confirmTitleColor"]) {
self.confirmTitleColor = [WXConvert UIColor:options[@"confirmTitleColor"]];
}
if (options[@"titleBackgroundColor"]) {
self.titleBackgroundColor = [WXConvert UIColor:options[@"titleBackgroundColor"]];
}
if (options[@"textColor"]) {
self.textColor = [WXConvert UIColor:options[@"textColor"]];
}
if (options[@"selectionColor"]) {
self.selectionColor = [WXConvert UIColor:options[@"selectionColor"]];
}
if (options[@"height"]) {
self.height = [WXConvert CGFloat:options[@"height"]];
}
if (items && [items count]>0 && [self isRightItems:items]) {
[self createPicker:items index:index];
self.callback = callback;
} else {
if (callback) {
callback(@{ @"result": @"error" },NO);
}
self.callback = nil;
}
}
- (void)handleA11yFocusback:(NSDictionary*)options
{
__weak typeof(self) weakSelf = self;
if (options[@"sourceRef"] && [options[@"sourceRef"] isKindOfClass:[NSString class]]) {
WXPerformBlockOnComponentThread(^{
WXComponent * focusBackComponent = [weakSelf.weexInstance componentForRef:options[@"sourceRef"]];
WXPerformBlockOnMainThread(^{
weakSelf.focusToView = focusBackComponent.view;
});
});
}
}
-(void)SetColorDelay:(NSNumber *)number
{
if(self.selectionColor) {
UILabel *labelSelected = (UILabel*)[self.picker viewForRow:[number integerValue] forComponent:0.3];
[labelSelected setBackgroundColor:self.selectionColor];
}
}
-(void)createPicker:(NSArray *)items index:(NSInteger)index
{
[self configPickerView];
self.items = [items copy];
self.index = index;
if (items && index < [items count]) {
[self.picker selectRow:index inComponent:0 animated:NO];
[self performSelector:@selector(SetColorDelay:) withObject:[NSNumber numberWithInteger:self.index] afterDelay:0.3];
} else if(items && [items count]>0) {
[self.picker selectRow:0 inComponent:0 animated:NO];
[self performSelector:@selector(SetColorDelay:) withObject:[NSNumber numberWithInteger:0] afterDelay:0.3];
}
[self show];
}
-(void)show
{
[[[UIApplication sharedApplication] keyWindow] endEditing:YES]; //hide keyboard
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:self.backgroundView];
if ([WXUtility enableAdaptiveLayout]) {
self.backgroundView.center = window.center;
}
if (self.isAnimating) {
return;
}
self.isAnimating = YES;
self.backgroundView.hidden = NO;
UIView * focusView = self.picker;
if([_pickerType isEqualToString:@"picker"]) {
focusView = self.picker;
} else {
focusView = self.datePicker;
}
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, focusView);
[UIView animateWithDuration:0.35f animations:^{
self.pickerView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height - WXPickerHeight, [UIScreen mainScreen].bounds.size.width, WXPickerHeight);
self.backgroundView.alpha = 1;
} completion:^(BOOL finished) {
self.isAnimating = NO;
}];
}
-(void)hide
{
if (self.isAnimating) {
return;
}
self.isAnimating = YES;
[UIView animateWithDuration:0.35f animations:^{
self.pickerView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width, WXPickerHeight);
self.backgroundView.alpha = 0;
} completion:^(BOOL finished) {
self.backgroundView.hidden = YES;
self.isAnimating = NO;
if (!_focusToView) {
_focusToView = self.backgroundView.superview;
}
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, _focusToView);
[self.backgroundView removeFromSuperview];
}];
}
-(void)cancel:(id)sender
{
[self hide];
if (self.callback) {
self.callback(@{ @"result": @"cancel"},NO);
self.callback=nil;
}
}
-(void)done:(id)sender
{
[self hide];
if (self.callback) {
self.callback(@{ @"result": @"success",@"data":[NSNumber numberWithInteger:self.index]},NO);
self.callback=nil;
}
}
-(BOOL)isRightItems:(NSArray *)array
{
for (id value in array) {
if([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]]) {
continue;
}else {
return NO;
}
}
return YES;
}
-(NSString *)convertItem:(id)value
{
if ([value isKindOfClass:[NSNumber class]]) {
return [NSString stringWithFormat:@"%ld",[value longValue]];
}
return value;
}
#pragma mark -
#pragma mark Picker View
-(void)configPickerView
{
self.backgroundView = [self createbackgroundView];
UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(hide)];
if (WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0") && WX_SYS_VERSION_LESS_THAN(@"11.1")) {
tapGesture.delegate = self;
}
[self.backgroundView addGestureRecognizer:tapGesture];
self.pickerView = [self createPickerView];
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, WXPickerToolBarHeight)];
toolBar.barTintColor = self.titleBackgroundColor?self.titleBackgroundColor:[UIColor whiteColor];
UIBarButtonItem* noSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
noSpace.width=10;
UIBarButtonItem* doneBtn ;
if (self.confirmTitle.length >0) {
doneBtn = [[UIBarButtonItem alloc] initWithTitle:self.confirmTitle style:UIBarButtonItemStylePlain target:self action:@selector(done:)];
}else {
doneBtn = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)];
}
if(self.confirmTitleColor){
doneBtn.tintColor = self.confirmTitleColor;
}
UIBarButtonItem *cancelBtn;
if (self.cancelTitle.length >0) {
cancelBtn = [[UIBarButtonItem alloc] initWithTitle:self.cancelTitle style:UIBarButtonItemStylePlain target:self action:@selector(cancel:)];
}else {
cancelBtn = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)];
}
if(self.cancelTitleColor){
cancelBtn.tintColor = self.cancelTitleColor;
}
UIBarButtonItem* flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolBar setItems:[NSArray arrayWithObjects:noSpace,cancelBtn,flexSpace,doneBtn,noSpace, nil]];
UILabel *titleLabel = [UILabel new];
titleLabel.frame = CGRectMake(0, 0, 200, WXPickerToolBarHeight);
titleLabel.center = toolBar.center;
titleLabel.textAlignment = NSTextAlignmentCenter;
if(self.titleColor){
titleLabel.textColor = self.titleColor;
}
if(self.title.length>0){
titleLabel.text = self.title;
[toolBar addSubview:titleLabel];
}
[self.pickerView addSubview:toolBar];
self.picker = [[UIPickerView alloc]init];
self.picker.delegate = self;
CGFloat height = WXPickerHeight;
if (WXFloatEqual(self.height, 0)){
height = self.height>WXPickerToolBarHeight?self.height:WXPickerHeight;
}
CGRect pickerFrame = CGRectMake(0, WXPickerToolBarHeight, [UIScreen mainScreen].bounds.size.width, height-WXPickerToolBarHeight);
self.picker.backgroundColor = [UIColor whiteColor];
self.picker.frame = pickerFrame;
[self.pickerView addSubview:self.picker];
[self.backgroundView addSubview:self.pickerView];
}
-(UIView *)createPickerView
{
UIView *view = [UIView new];
CGFloat height = WXPickerHeight;
if (WXFloatEqual(self.height, 0)){
height = self.height>WXPickerToolBarHeight?self.height:WXPickerHeight;
}
view.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width, height);
view.backgroundColor = [UIColor whiteColor];
return view;
}
-(UIView *)createbackgroundView
{
UIView *view = [UIView new];
view.frame = [UIScreen mainScreen].bounds;
view.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.4];
return view;
}
#pragma mark -
#pragma UIPickerDelegate
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [self.items count];
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
return 44.0f;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [self convertItem:self.items[row]];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
self.index = row;
if(self.selectionColor) {
UILabel *labelSelected = (UILabel*)[pickerView viewForRow:row forComponent:component];
[labelSelected setBackgroundColor:self.selectionColor];
}
}
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *label = (id)view;
if (!label)
{
label= [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [pickerView rowSizeForComponent:component].width, [pickerView rowSizeForComponent:component].height)];
label.textAlignment = NSTextAlignmentCenter;
UIColor *color = self.textColor?self.textColor:[UIColor blackColor];
label.textColor = color;
label.text = [self convertItem:self.items[row]];
}
return label;
}
#pragma mark -
#pragma Date & Time Picker
-(void)pickDate:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback
{
if (UIAccessibilityIsVoiceOverRunning()) {
[self handleA11yFocusback:options];
}
_pickerType = @"pickDate";
self.datePickerMode = UIDatePickerModeDate;
[self datepick:options callback:callback];
}
-(void)pickTime:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback
{
if (UIAccessibilityIsVoiceOverRunning()) {
[self handleA11yFocusback:options];
}
_pickerType = @"pickTime";
self.datePickerMode = UIDatePickerModeTime;
[self datepick:options callback:callback];
}
-(void)datepick:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback
{
if ((UIDatePickerModeTime == self.datePickerMode) || (UIDatePickerModeDate == self.datePickerMode)) {
[self createDatePicker:options callback:callback];
} else {
if (callback) {
callback(@{ @"result": @"error" },NO);
}
self.callback = nil;
}
}
- (void)createDatePicker:(NSDictionary *)options callback:(WXModuleKeepAliveCallback)callback
{
self.callback = callback;
self.datePicker = [[UIDatePicker alloc]init];
#ifdef __IPHONE_13_4
if (@available(iOS 13.4, *)) {
self.datePicker.preferredDatePickerStyle = UIDatePickerStyleWheels;
}
#endif
if (UIDatePickerModeDate == self.datePickerMode) {
self.datePicker.datePickerMode = UIDatePickerModeDate;
NSString *value = [WXConvert NSString:options[@"value"]];
if (value) {
NSDate *date = [WXUtility dateStringToDate:value];
if (date) {
self.datePicker.date =date;
}
}
NSString *max = [WXConvert NSString:options[@"max"]];
if (max) {
NSDate *date = [WXUtility dateStringToDate:max];
if (date) {
self.datePicker.maximumDate =date;
}
}
NSString *min = [WXConvert NSString:options[@"min"]];
if (min) {
NSDate *date = [WXUtility dateStringToDate:min];
if (date) {
self.datePicker.minimumDate =date;
}
}
} else if (UIDatePickerModeTime == self.datePickerMode) {
self.datePicker.datePickerMode = UIDatePickerModeTime;
NSString *value = [WXConvert NSString:options[@"value"]];
if (value) {
NSDate *date = [WXUtility timeStringToDate:value];
if (date) {
self.datePicker.date = date;
}
}
}
[self configDatePickerView];
[self show];
}
-(void)configDatePickerView
{
self.backgroundView = [self createbackgroundView];
UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(hide)];
if (WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0") && WX_SYS_VERSION_LESS_THAN(@"11.1")) {
tapGesture.delegate = self;
}
[self.backgroundView addGestureRecognizer:tapGesture];
self.pickerView = [self createPickerView];
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, WXPickerToolBarHeight)];
[toolBar setBackgroundColor:[UIColor whiteColor]];
UIBarButtonItem* noSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
noSpace.width=10;
UIBarButtonItem* doneBtn = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneDatePicker:)];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem* cancelBtn = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelDatePicker:)];
[toolBar setItems:[NSArray arrayWithObjects:noSpace,cancelBtn,flexSpace,doneBtn,noSpace, nil]];
[self.pickerView addSubview:toolBar];
CGRect pickerFrame = CGRectMake(0, WXPickerToolBarHeight, [UIScreen mainScreen].bounds.size.width, WXPickerHeight-WXPickerToolBarHeight);
self.datePicker.frame = pickerFrame;
self.datePicker.backgroundColor = [UIColor whiteColor];
[self.pickerView addSubview:self.datePicker];
[self.backgroundView addSubview:self.pickerView];
}
-(void)cancelDatePicker:(id)sender
{
[self hide];
if (self.callback) {
self.callback(@{ @"result": @"cancel"},NO);
self.callback = nil;
}
}
-(void)doneDatePicker:(id)sender
{
[self hide];
NSString *value = @"";
if (UIDatePickerModeTime == self.datePicker.datePickerMode) {
value = [WXUtility timeToString:self.datePicker.date];
} else if(UIDatePickerModeDate == self.datePicker.datePickerMode)
{
value = [WXUtility dateToString:self.datePicker.date];
}
if (self.callback) {
self.callback(@{ @"result": @"success",@"data":value},NO);
self.callback=nil;
}
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (self.pickerView && [touch.view isDescendantOfView:self.pickerView]) {
return NO;
}
return YES;
}
@end