Again, take a look at the renderings
First of all, according to the effect, we can analyze, how to achieve such an effect, in fact, no matter what the UI effect, the first step is to analyze how we achieve this, and then how to achieve this effect better, the code is more clear and concise, higher scalability.
- First, we need a fully masked background that hides the Actionsheet when clicked
- And then this actionsheet, it needs to be generated based on the options, and you can imagine that the options are buttons, and I’ve seen some implementations that make it a TableView, and I feel like I’m in trouble
- The other one is click callbacks, and I’ve done two of them here, delegate callbacks and block callbacks
Correction of the item
In many actionsheet implementations, the callback is an index value. My previous implementation is also a click index, but it is difficult to expand and has limitations. Therefore, this time, I made the callback into a Model, in which you can define some properties by yourself, according to the parameters passed in, Customize the model, which makes it a little more extensible
@interface PPSActionSheetItem : NSObject @property (nonatomic, readonly, copy) NSString *title; // hit tit@property (nonatomic, ReadOnly, assign) NSInteger index; // click index + (PPSActionSheetItem *)itemWithTitle:(NSString *)title index:(NSInteger)index; @end @interface PPSActionSheetItem() @property (nonatomic, readwrite, copy) NSString *title; // hit tit@property (nonatomic, ReadWrite, assign) NSInteger index; // index @end@implementation PPSActionSheetItem + (PPSActionSheetItem *)itemWithTitle:(NSString *)title index:(NSInteger)index { PPSActionSheetItem *item = [[PPSActionSheetItem alloc] initWithTitle:title index:index]; return item; } - (instancetype)initWithTitle:(NSString *)title index:(NSInteger)index { self = [super init]; if(self) { _title = [title copy]; _index = index; } return self; } @endCopy the code
delegate && block
Click on the callback, it’s the same as before, except that the callback is item, right
delegate
@class PPSActionSheet; @class PPSActionSheetItem; @ protocol PPSActionSheetClickedDelegate @ required / * * click options The agent must implement this method Otherwise click cannot achieve @ param actionSheet actionSheet the currently displayed actionsheet@param item click position */ - (void) actionsheet :(PPSActionSheet *) actionsheet clickedButtonAtIndex:(PPSActionSheetItem *)item; @endCopy the code
block
// Click the callback typedef void(^ClickedCompleteBlock)(PPSActionSheetItem *item);Copy the code
implementation
Initialize the
When you initialize, you provide an initialization method, and if you want to use block callbacks, you just set the delegate to nil
The initialization method option takes the form of passing in mutable parameters, which makes initialization more concise
/** Create instance, If you're using a block, the delegate is just passing nil. @param delegate delegate is usually for the current VC @param cancleTitle the bottom title option @param otherTitles and some other option titles @return actionsheet */ - (instancetype)initWithDelegate:(id)delegate cancleTitle:(NSString *)cancleTitle otherTitles:(NSString *)otherTitles,... NS_REQUIRES_NIL_TERMINATION;Copy the code
Effect of implementation
The entire Actionsheet is inherited from UIView, the black mask we talked about earlier, I set the ActionSheet itself as a full-screen view, add a background color effect to it, and then alpha it, and that’s it.
And then the view options, add them to a sub-View sheetView of the ActionSheet
During initialization, the option item is first generated from the parameter passed in
int tag = 0; _items = [NSMutableArray array]; PPSActionSheetItem *cancleItem = [PPSActionSheetItem itemWithTitle:@" Cancel "index:0]; [_items addObject:cancleItem]; tag ++; NSString* curStr; va_list list; if(otherTitles) { PPSActionSheetItem *item = [PPSActionSheetItem itemWithTitle:otherTitles index:tag]; [_items addObject:item]; tag ++; va_start(list, otherTitles); while ((curStr = va_arg(list, NSString*))) { PPSActionSheetItem *item = [PPSActionSheetItem itemWithTitle:curStr index:tag]; [_items addObject:item]; tag ++; } va_end(list); }Copy the code
After the option item is generated, we need to calculate the SheetView frame and start adding buttons to the SheetView
CGRect sheetViewF = _sheetView.frame; sheetViewF.size.height = BtnHeight * _items.count + CancleMargin; _sheetView.frame = sheetViewF; // Start adding buttons [self setupBtnWithTitles];Copy the code
When adding buttons, just count the frame for each button and add it to sheetView. It’s a no-hassle implementation
/** Create each option */ - (void)setupBtnWithTitles {for (PPSActionSheetItem *item in _items) {UIButton * BTN = nil; If (item.index == 0) {// Cancel button BTN = [[UIButton alloc] initWithFrame:CGRectMake(0, _sheetView.frame.size.height - BtnHeight, PPSActionSheetScreenWidth, BtnHeight)]; } else { btn = [[UIButton alloc] initWithFrame:CGRectMake(0, BtnHeight * (item.index - 1) , PPSActionSheetScreenWidth, BtnHeight)]; / / the top painting line UIView * line = [[UIView alloc] initWithFrame: CGRectMake (0, 0, PPSActionSheetScreenWidth, 0.5)]. line.backgroundColor = PPSActionSheetSeparatorColor; [btn addSubview:line]; } btn.tag = item.index; [btn setBackgroundImage:PPSActionSheetNormalImage forState:UIControlStateNormal]; [btn setBackgroundImage:PPSActionSheetHighImage forState:UIControlStateHighlighted]; [btn setTitle:item.title forState:UIControlStateNormal]; btn.titleLabel.font = [UIFont fontWithName:@"STHeitiSC-Light" size:17]; [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(sheetBtnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.sheetView addSubview:btn]; }}Copy the code
You can use blocks or a delegate
PPSActionSheet *sheet1 = [[PPSActionSheet alloc] initWithDelegate:nil cancleTitle:@" Cancel "otherTitles:@" hello ",@" HELLO ", nil]; sheet1.clickedCompleteBlock = ^(PPSActionSheetItem *item) { UIAlertView *alert = [[UIAlertView alloc] InitWithTitle :item.title message:@" click item" Delegate :nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; NSLog(@"%@", item.title); }; [sheet1 show];Copy the code
The actionsheet can also be rich, such as passing in the main title, subtitle and so on, or it can be enriched into a specific number of items to choose, or a control switch for several options, etc. Have this idea, the following should be to start with the main and subtitle
There is no more to say. This Actionsheet is also used when using the image browser, and when I saw that the previous one was a little ugly, I cleaned it up a little bit. The little tool for viewing images will also be reorganized and optimized. There is also a small view of progress downloaded from the picture viewer, and I plan to separate that view into a warehouse. These small views can be optimized and enriched a lot, so I will bring them out for preparation
I’ll put the source code there:
Github.com/yangqian111…
Welcome to ppsheep_Qian
weibo.com/ppsheep
Welcome to the public account