Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article also participated in the “Digitalstar Project” to win a creative gift package and creative incentive money
preface
1. Implementation idea of popup menu that supports expansion and folding:
1.1 Add popup view to keyWindow and mask to main window (the main reason is to hide the popup view by clicking on a blank area of the screen)
1.2 When displaying, the animation extends from the upper right corner to the lower left foot; When hidden, the animation retracts from the bottom left foot to the top right corner (when displayed, it grows from top down, i.e. X,y)
1.3 The layout of the internal view is collectionView
1.4 The frame of view is calculated and transformed according to the commodity cell where the menu button is currently clicked.
/** Triggers the collapse menu to hide and show the button */
@property (nonatomic.weak) UIButton *btn;
/** is used to calculate the folding menu frame, */
@property (nonatomic.weak) UIButton *tmpbtn;
Copy the code
2. Application scenario of horizontal pop-up menu view:
2.1 Supported functions of goods in stores: expand the view horizontally to the right (operation: down/on the shelf, print, edit, synchronize the network) and fold the hidden view again
2.2 Online goods currently only include the function of taking off: Expand the folding view: (including the function of taking off/taking off goods)
- Vertical popup menu view
The top right-hand corner of the popup menu: member module drop-down menu (vertical) kunnan.blog.csdn.net/article/det…
Video: live.csdn.net/v/173757
Not download address: download.csdn.net/download/u0…
Demo sets two test switches:
Test switch 1: Integrate the horizontal pop-up menu view into the cell
Test switch 2: integrate the horizontal pop-up menu View into the VC View
Demo2 download address: download.csdn.net/download/u0…
Demo2 integrates the horizontal pop-up menu View into the VC View
Answer the question, please pay attention to the public number: iOS reverse
I. The implementation idea of the pop-up menu that supports expansion and folding
1.1 Add popup view to keyWindow and mask to main window (the main reason is to hide the popup view by clicking on a blank area of the screen)
#define kWindow [UIApplication sharedApplication].keyWindow
[kWindow addSubview:self];
[kWindow addSubview:self.cover];// Add a mask to the main window that listens for click events to hide the popup view
Copy the code
1.2 a
When shown, the animation extends from the upper right corner to the lower left foot; When hidden, the animation retracts from the bottom left foot to the top right corner (when displayed, it grows from top down, i.e. X,y)
Implementation principle of expansion effect:
1. When clicking the pop-up button above the cell displaying product information, the shadow alpha changes from 0 to 1, and the scale of the popover changes from 0 to 1 (CABasicAnimation is used here).
2 Click on the blank area (selsel. cover), and then change the shadow alpha from 1 to 0 and the popover scale from 1 to 0 (again using CABasicAnimation). Remove the shadow and popover when the animation is complete
1.3 The layout of the internal view is collectionView
@property (strong.nonatomic) UICollectionView *collectionView;
Copy the code
1.4 The frame of view is calculated and transformed according to the commodity cell where the menu button is currently clicked.
CGRect endRect = [weakSelf.btn.superview convertRect:weakSelf.btn.frame toView:kWindow];
CGRect Rect = [weakSelf.tmpbtn.superview convertRect:weakSelf.tmpbtn.frame toView:kWindow];
// Set the menu frame
weakSelf.models.rect = Rect;
weakSelf.models.endRect = endRect;// End position
[[[weakSelf models].viewModel expandMenuSubject] sendNext:weakSelf.models];
}];
Copy the code
II, usage,
2.1 Create popmenuView
- Build the data model inside the menu
+ (NSMutableArray*)getMenudatas4MiniAppWithBlock:(void(^) (id sender))block{
NSMutableArray* tmp = [NSMutableArray array];
QCTCollectionModel *network = [QCTCollectionModel new];
network.titleName = QCTLocal(@"Shelves_key");
network.imgName= @"icon_sp_shangjia";
network.block = block;
network.type =QCTCollectionModelType4Shelves;
[tmp addObject:network];
return tmp;
}
Copy the code
- Lazy loading of popmenuView
#pragmaMark-******** supports a collapsed-up menu view
- (QCTHorizontalpopupView *)popmenuView{
if(! _popmenuView) { _popmenuView = [[QCTHorizontalpopupView alloc] initWithFrame:self.view.frame viewModel:self.viewModel];
_popmenuView.hidden = YES;
#pragmaMark-******** Builds the model of the collapsed view
__weak __typeof__(self) weakSelf = self;
self.viewModel.Menudatas = [QCTCollectionModel getMenudatas4MiniAppWithBlock:^( QCTCollectionModel * sender) {
[[[weakSelf viewModel] hiddenSubject]sendNext:nil];
NSLog(@" Clicked %@",[sender titleName]);
switch (sender.type) {
case QCTCollectionModelType4edit:
{
[weakSelf setupQCTEditMerchandiseViewController:sender];
}
break;
case QCTCollectionModelType4Shelves:
// ** ** */
{
// Jump to the interface according to different commodity types
[weakSelf setupQCTCollectionModelType4Shelves:sender];
}
break;
case QCTCollectionModelType4Offtheshelf:
{
// Jump to the interface according to different commodity types
[weakSelf setupQCTCollectionModelType4Shelves:sender];
}
break;
// ** Print */
case QCTCollectionModelType4Printer:
{
/ / print
[weakSelf printerInfo:self.popmenuView.model];
}
break;
default:
break; }}]; _popmenuView.models =self.viewModel.Menudatas;
}
return _popmenuView;
}
Copy the code
2.2 Listening for eject and collapse events
/** Listen for the pop-up event emitted by the cell that displays product information. * /
[self.viewModel.showMenuSubject subscribeNext:^(QCTgoodsManListModel * x) {
[weakSelf.popmenuView updateRect: x.rect ];// Update the popmenuView position.
[weakSelf.popmenuView updateendRect: x.endRect ];// Sets the end of the folding animation
[weakSelf.popmenuView expandView:x.expandViewCGPoint ];
}];
/** Collapse popup menu */
[self.viewModel.hiddenSubject subscribeNext:^(id _Nullable x) {
[weakSelf.popmenuView foldView];
}];
// Monitor the popup menu button click to determine whether to expand or hide
[self.viewModel.expandMenuSubject subscribeNext:^(id _Nullable x) {
[weakSelf expandMenu:x];
}];
Copy the code
- Decide whether to expand the pop-up menu or collapse it
#pragmaMark-******** Decide whether to expand the pop-up menu or collapse it
- (void)expandMenu:(id)x{// Click the button
self.popmenuView.model = x;
[ self.viewModel.reloadSubject sendNext:nil];
if ([self.popmenuView isHidden]) {
[self.viewModel.showMenuSubject sendNext:x];
}else{[self.viewModel.hiddenSubject sendNext:nil]; }}Copy the code
III. Complete Demo
Demo sets two test switches
[self addpopV2cell]; // [self addpopV2VCView]; // Test switch 2: integrate the horizontal pop-up menu View into the VC ViewCopy the code
3.1 Demo1: Integrate the horizontal pop-up menu view into the cell
Not download address: download.csdn.net/download/u0… Answer the question, please pay attention to the public number: iOS reverse
3.2 DEMO2: Integrate the horizontal pop-up menu View into the VC View
Article: kunnan.blog.csdn.net/article/det… Video: live.csdn.net/v/173757 demo2 download address: download.csdn.net/download/u0… Answer the question, please pay attention to the public number: iOS reverse
1. Implementation idea of popup menu that supports expansion and folding:
1.1 Add popup view to keyWindow and mask to main window (the main reason is to hide the popup view by clicking on a blank area of the screen)
1.2 When displaying, the animation extends from the upper right corner to the lower left foot; When hidden, the animation is recovered from the lower left foot to the upper right corner (when displayed, it is from the top down, that is, X and Y gradually become larger). 1.3 Internal view adopts collectionView for layout. 1.4 The frame of view is calculated and transformed according to the commodity cell where the menu button is currently clicked.
2. Application scenario of horizontal pop-up menu view:
2.1 Supported functions of goods in stores: expand the view horizontally to the right (operation: down/on the shelf, print, edit, synchronize the network) and fold the hidden view again
2.2 Online goods currently only include the function of taking off: Expand the folding view: (including the function of taking off/taking off goods)
3.3 Pop-up menu view in horizontal direction
Popup menu HorizontalpopupView specific code
- .h
#import <UIKit/UIKit.h>
#import "QCTgoodsManListModel.h"
#import "QCThorizontalMenuCollectionViewCell.h"
#import "QCTgoodsListViewModel.h"
NS_ASSUME_NONNULL_BEGIN
Similar Popup menu in this APP: the drop-down menu (vertical) in the upper right corner of the membership module. Scenario: 0.1. Online goods currently only include the function of takedown: Expand the folding view: (including the function of taking up and takedown goods). 0.2 Supported functions of goods in stores: expand view horizontally to the right (operation: down/on shelves, print, edit, synchronize network) Support folding and hiding view II. 1. Add view to keyWindow #define kWindow [UIApplication sharedApplication]. KeyWindow [kWindow addSubview:self]; #define kWindow [UIApplication sharedApplication]. [kWindow addSubview:self.cover]; 2. Expand effect: When displaying, the animation extends from the upper right corner to the lower left foot; When hidden, the animation is withdrawn from the lower left foot to the upper right corner // (when displayed, the animation is displayed from the top down, that is, X and Y gradually become larger) When I click on the Eject button, the shadow alpha goes from 0 to 1, and the popover scale goes from 0 to 1 (CABasicAnimation). Click on the blank area, and then make the shadow alpha go from 1 to 0, and the popover scale goes from 1 to 0 (also CABasicAnimation). 4. The frame of view is calculated and transformed according to the commodity cell where the menu button is currently clicked. [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) { // Get _btn in Windows frame CGRect endRect = [weakSelf. BTN. Superview convertRect: weakSelf. The BTN. Frame toView: kWindow]; CGRect Rect = [weakSelf.tmpbtn.superview convertRect:weakSelf.tmpbtn.frame toView:kWindow]; Weakself.models. Rect = rect; Weakself.models. EndRect = endRect; [[[weakSelf models]. ViewModel expandMenuSubject] sendNext:weakSelf. Models];}]; * /
@interface QCTHorizontalpopupView : UIView
/** Commodity data stores commodity information. Used for printing, loading and unloading, editing, etc. */
@property (nonatomic.strong) QCTgoodsManListModel* model;
/** Menu view model data */
@property (nonatomic.strong) NSMutableArray* models;
@property (nonatomic.copy) void (^block)(id sender);
@property (nonatomic.strong) QCTgoodsListViewModel *viewModel;
- (id)initWithFrame:(CGRect)frame viewModel:(id)viewModel ;
/** Update menu frame. You need to set the lower width */ according to the Models Settings
- (void)updateRect:(CGRect)rect;
/** Update the end position of the folding animation */
- (void)updateendRect:(CGRect)rect;
/** expand method */
- (void)expandView:(CGPoint)AnchorPoint;
/** folding method */
- (void)foldView;
@end
NS_ASSUME_NONNULL_END
Copy the code
- m
#import "QCTHorizontalpopupView.h"
@interface QCTHorizontalpopupView(a)
/**
*/
@property (strong.nonatomic) UICollectionView *collectionView;
@property (strong.nonatomic) NSIndexPath *indexPath;
/** mask, used to handle clicking on the blank area (i.e. not the popup menu part) */
@property (nonatomic.weak) UIView *cover;
/** Popup menu horizontal arrow */
@property (nonatomic.strong) UIImageView *img;
/** Stores the View */ where the folding animation ends
@property (nonatomic.strong) UIView *clickView;
@end
@implementation QCTHorizontalpopupView
- (UIView *)clickView{
if (nil == _clickView) {
UIView *tmpView = [[UIView alloc]init];
_clickView = tmpView;
[self addSubview:_clickView];
tmpView.backgroundColor = [UIColor clearColor];
tmpView.alpha = 0;
__weak __typeof__(self) weakSelf = self;
[tmpView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(weakSelf).offset(0);
make.size.mas_equalTo(CGSizeMake(kAdjustRatio(10), kAdjustRatio(10)));
make.left.equalTo(weakSelf.img.mas_right).offset(kAdjustRatio(5));
}];
}
return _clickView;
}
// Background image menu arrow- (UIImageView *)img{//icon_huiyuanka_sanjiao
if(! _img) { _img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_sp_sanjiao"]].//
[self addSubview:_img];
__weak __typeof__(self) weakSelf = self;
[_img mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(weakSelf).offset(0);
make.left.equalTo(weakSelf.mas_right).offset(-kAdjustRatio(0));
}];
}
return _img;
}
/** Mask is used to listen for click events to hide the pop-up view */- (UIView *)cover{
if(! _cover) {UIView *tmp = [[UIView alloc] initWithFrame:kWindow.bounds];
_cover = tmp;
_cover.backgroundColor = [UIColor clearColor];
[kWindow addSubview:self.cover];// Add the mask to the main window
_cover.hidden = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(removeMenuList)];
[_cover addGestureRecognizer:tap];
}
return _cover;
}
- (void)setViewModel:(QCTgoodsListViewModel *)viewModel{
_viewModel = viewModel;
}
- (id)init {
return [self initWithFrame:CGRectZero viewModel:nil];
}
- (id)initWithFrame:(CGRect)frame {
return [self initWithFrame:frame viewModel:nil];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
return [self initWithFrame:CGRectZero viewModel:nil];
}
- (id)initWithViewModel:(id)viewModel {
return [self initWithFrame:CGRectZero viewModel:viewModel];
}
- (id)initWithFrame:(CGRect)frame viewModel:(id)viewModel {
if (self = [super initWithFrame:frame]) {
self.viewModel = viewModel;
[self bindViewModel];
[self collectionView];
[self cover];
[self img];
[self clickView];
}
return self;
}
- (void)bindViewModel {
@weakify(self);
__weak __typeof__(self) weakSelf = self;
[self.viewModel.reloadSubject subscribeNext:^(id _Nullable x) {
@strongify(self);
[self.collectionView reloadData];
}];
}
- (void)updateendRect:(CGRect)rect{
self.clickView.frame = rect;
}
/** Update frame. Rect by write, x and y by cell position of the currently selected item. * /
- (void)updateRect:(CGRect)rect{
self.frame = rect;
[self updateFocusIfNeeded];
[self.collectionView updateConstraints];
[self.collectionView layoutIfNeeded];
[self layoutSubviews];
}
/** NSMutableArray */
- (void)setModels:(NSMutableArray*)models{
_models = models;
[self.collectionView reloadData];
}
- (UICollectionView *)collectionView {
if (_collectionView == nil) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
// 2. Set the inner margin of the entire collectionView
// Are up, left, down, and right respectively
// flowLayout.sectionInset = UIEdgeInsetsMake(0,kAdjustRatio(10),0,kAdjustRatio(10));
//. Set the spacing between each line
flowLayout.minimumLineSpacing = 0;
flowLayout.minimumInteritemSpacing = 0;
// FlowLayout. itemSize = CGSizeMake((SCREEN_WIDTH-3*kAdjustRatio(10))/3.0, self.optionsView.height);
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
// _collectionView.backgroundColor = [UIColor clearColor];
UIView *style = _collectionView;
style.layer.cornerRadius = 3;
style.layer.backgroundColor = [[UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:1.0f] CGColor];
style.alpha = 0.8;
_collectionView.showsVerticalScrollIndicator = NO;
_collectionView.bounces = NO;
_collectionView.dataSource = self;
_collectionView.delegate = self;
[_collectionView registerClass:[QCThorizontalMenuCollectionViewCell class] forCellWithReuseIdentifier:@"QCThorizontalMenuCollectionViewCell"];
if (@available(iOS 11.0, *)) {
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}
_collectionView.scrollEnabled = NO;
__weak __typeof__(self) weakSelf = self;
[self addSubview:_collectionView];
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.bottom.right.equalTo(weakSelf);
}];
}
return _collectionView;
}
#pragma mark - UICollectionViewDelegate
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.models.count; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size;
//
size = CGSizeMake(self.collectionView.width/self.models.count, kAdjustRatio(kHorizontalpopupViewH));//kHorizontalpopupViewH
// size = CGSizeMake(self.collectionView.width/3, kAdjustRatio(50));
return size;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
QCThorizontalMenuCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QCThorizontalMenuCollectionViewCell" forIndexPath:indexPath];
QCTCollectionModel *model = self.models[indexPath.row];
//
// ** ** */
// QCTCollectionModelType4Shelves,
// /**下架*/
// QCTCollectionModelType4Offtheshelf,
//
//
if(model.type == QCTCollectionModelType4Shelves || model.type == QCTCollectionModelType4Offtheshelf ){
if(!self.model.state.boolValue){
model.titleName = QCTLocal(@"Shelves_key");
// @" ";
model.imgName = @"icon_sp_shangjia";
model.type = QCTCollectionModelType4Shelves;
}else{
model.type = QCTCollectionModelType4Offtheshelf;
model.titleName = QCTLocal(@"Off_the_shelf");
// @" delete ";
model.imgName = @"icon_sp_xiajia";
}
}
cell.model =model;
cell.goodmodel = self.model;
return cell;
}
#pragmaAnimation: Set layer.anchorPoint
+ (void) setAnchorPoint:(CGPoint)anchorpoint forView:(UIView *)view{
CGRect oldFrame = view.frame;
view.layer.anchorPoint = anchorpoint;
view.frame = oldFrame;
}
/** When you click the eject button, the shadow alpha will go from 0 to 1 and the popover scale will go from 0 to 1 (CABasicAnimation). // When displaying, the animation extends from the upper right corner to the lower left foot; When hidden, the animation is retracted from the lower left foot to the upper right corner
- (void)expandView:(CGPoint)AnchorPoint{
[self removeFromSuperview];
[kWindow addSubview:self];
[self.cover removeFromSuperview];
[kWindow addSubview:self.cover];// Add the mask to the main window
[kWindow bringSubviewToFront:self];
// Display the animation from the upper right corner to the lower left foot; When hidden, the animation is retracted from the lower left foot to the upper right corner
// (x,y, x,y)
[[self class] setAnchorPoint:CGPointMake(1.f, 0.5f) forView:self];
self.transform = CGAffineTransformMakeScale(0.001f, 0.001f);
self.hidden = NO;// Change to animation, MemberCardMenuView provides an instance method of the animation
self.cover.hidden = NO;
self.cover.alpha = 0;
[UIView animateWithDuration:0.3 animations:^{
self.transform = CGAffineTransformMakeScale(1.f, 1.f);
self.cover.alpha = 1;
} completion:^(BOOL finished) {
self.transform = CGAffineTransformIdentity; }]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.viewModel.hiddenSubject sendNext:nil];
}
/ * * folding * /
- (void)foldView{
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[UIView animateWithDuration:0.3 animations:^{
self.transform = CGAffineTransformMakeScale(0.001f, 0.001f);
self.cover.alpha = 0;
} completion:^(BOOL finished) {
self.hidden = YES;
self.cover.hidden = YES;
self.transform = CGAffineTransformIdentity;
[self removeFromSuperview];
[self.cover removeFromSuperview];
}];
}
#pragmaMark - Remove menu- (void)removeMenuList{
[self.viewModel.hiddenSubject sendNext:nil];
}
@end
Copy the code
3.4 Integrating into the Cell
Fans wonder if it can be used in cell click events
A: yes, please refer to the examples in this paper, the integration of QCTQCTgoodsListTableViewCellView
You can also control the click priority using the cancelsTouchesInView attribute. Case: iOS Settings of the tableView click priority is lower than the cell selected events [scene: screening of view, for example, to monitor the click event of the mask is hidden screening view 】 blog.csdn.net/z929118967/…
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
[[tap rac_gestureSignal] subscribeNext:^(id x) {
@strongify(self);
if (self.alpha) {
[self.viewModel.hiddenSubject sendNext:nil]; }}]; [self addGestureRecognizer:tap];
UITapGestureRecognizer *cutTap = [[UITapGestureRecognizer alloc] init];
cutTap.cancelsTouchesInView = NO;// Set the click event priority of the tableView lower than the selected event of the cell
[[cutTap rac_gestureSignal] subscribeNext:^(id x) {
// @strongify(self);
[self.viewModel.hiddenSubject sendNext:nil];
}];
[self.tableView addGestureRecognizer:cutTap];
Copy the code
QCTQCTgoodsListTableViewCellView
Integrated into the cell
#import "QCTQCTgoodsListTableViewCellView.h"
/** Display product information */
@interface QCTQCTgoodsListTableViewCellView(a)
@property (strong.nonatomic) UIImageView *iconImgV;
@property (nonatomic.weak) UILabel *titleLab;
@property (nonatomic.weak) UILabel *barCodeTitleLab;//
@property (nonatomic.weak) UILabel *priceLab;
@property (nonatomic.weak) UILabel *skuLab;/ / inventory
/** Collapse menu button */
@property (nonatomic.weak) UIButton *btn;/ / more
/** is used to calculate the folding menu frame, */
@property (nonatomic.weak) UIButton *tmpbtn;//
@property (nonatomic.weak) UIView *linView;//
@end
@implementation QCTQCTgoodsListTableViewCellView
// View the complete code from demo
@end
Copy the code
see also
- Vertical popup menu view
The top right-hand corner of the popup menu: member module drop-down menu (vertical) kunnan.blog.csdn.net/article/det…
- [Click the title of the navigation bar and drop down to select a category] The left side of the title button of the iOS navigation bar is the category name and the right side is the drop-down icon
Blog.csdn.net/z929118967/…
For more information and services, please check out # Applets: iOS Reverse, only for you to present valuable information, focusing on mobile technology research field.