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