附近网站建设,太平保宝app免费下载二维码,手工艺品外贸出口公司网站建设方案,app界面设计规范iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果
之前开发中遇到需要使用实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 一、效果图 二、CAShapeLayer与UIBezierPath
2.1、CAShapeLayer是什么#xff1f;
CAShapeLayer继承自…iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果
之前开发中遇到需要使用实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 一、效果图 二、CAShapeLayer与UIBezierPath
2.1、CAShapeLayer是什么
CAShapeLayer继承自CALayer可使用CALayer的所有属性 CAShapeLayer需要和UIBezierPath绘制图形。
创建shapeLayer
// 创建 shapeLayer
CAShapeLayer *shapeLayer [[CAShapeLayer alloc]init];
[self.view.layer addSublayer:shapeLayer];
shapeLayer.path path.CGPath;
shapeLayer.fillColor [UIColor clearColor].CGColor;
shapeLayer.strokeColor [UIColor blackColor].CGColor;
shapeLayer.lineWidth 5;2.2、UIBezierPath是什么
UIBezierPath即贝塞尔曲线 UIBezierPath 类允许你在自定义的 View 中绘制和渲染由直线和曲线组成的路径 (instancetype)bezierPath;(instancetype)bezierPathWithRect:(CGRect)rect;(instancetype)bezierPathWithOvalInRect:(CGRect)rect;(instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius(instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;(instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;(instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;三、绘制箭头
在弹出的菜单弹出时候会显示箭头这里使用UIBezierPath和CAShapeLayer绘制箭头。
#pragma mark - DrawShapeLayer
- (void)drawShapeLayer {CGFloat startPointX self.contentStartPoint.x;CGFloat startPointY self.contentStartPoint.y;CGFloat width CGRectGetWidth(self.contentBGImageView.frame);CGFloat height CGRectGetHeight(self.contentBGImageView.frame);self.path [UIBezierPath bezierPath]; // 创建路径[self.path moveToPoint:CGPointMake(startPointX, startPointY)]; // 设置起始点[self.path addLineToPoint:CGPointMake(startPointX 5.0, kAnchorHeight)];[self.path addLineToPoint:CGPointMake(width - 5.0, kAnchorHeight)];[self.path addArcWithCenter:CGPointMake(width - 5.0, kAnchorHeight 5.0) radius:5 startAngle:KCP*3/2 endAngle:2*KCP clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(width, height - 5.0)];[self.path addArcWithCenter:CGPointMake(width - 5.0, height - 5.0) radius:5 startAngle:0 endAngle:KCP/2 clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(5, height)];[self.path addArcWithCenter:CGPointMake(5.0, height-5.0) radius:5 startAngle:KCP/2 endAngle:KCP clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(0.0, kAnchorHeight 5.0)];[self.path addArcWithCenter:CGPointMake(5, kAnchorHeight 5) radius:5 startAngle:KCP endAngle:KCP*3/2 clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(startPointX - 5.0, kAnchorHeight)];[self.path addLineToPoint:CGPointMake(startPointX, startPointY)];self.path.lineWidth 2.f;self.path.lineCapStyle kCGLineCapRound;self.path.lineJoinStyle kCGLineCapRound;[self.path closePath]; // 封闭未形成闭环的路径UIGraphicsBeginImageContext(self.contentBGImageView.bounds.size);[self.path stroke];UIGraphicsEndImageContext();self.shapeLayer.path self.path.CGPath;
}四、点击触摸的mask处理
当下拉菜单显示后MaskView上实现touchesBegan可以点击触摸可以隐藏菜单
INNoteZoneOptionMaskView.h
#import UIKit/UIKit.h
#import Foundation/Foundation.hprotocol INNoteZoneOptionMaskViewDelegate;
interface INNoteZoneOptionMaskView : UIViewproperty (nonatomic, weak) idINNoteZoneOptionMaskViewDelegatemaskDelegate;endprotocol INNoteZoneOptionMaskViewDelegate NSObject- (void)optionMaskTouched;endINNoteZoneOptionMaskView.m
#import INNoteZoneOptionMaskView.himplementation INNoteZoneOptionMaskView- (void)touchesBegan:(NSSetUITouch * *)touches withEvent:(nullable UIEvent *)event {// 1.自己先处理事件...if (self.maskDelegate [self.maskDelegate respondsToSelector:selector(optionMaskTouched)]) {[self.maskDelegate optionMaskTouched];}// 2.再调用系统的默认做法再把事件交给上一个响应者处理[super touchesBegan:touches withEvent:event];
}end五、菜单显示
控件显示在keyWindow上
[[UIApplication sharedApplication].keyWindow addSubview:self];显示动画
- (void)showOption {self.hidden NO;CGPoint anchorPoint CGPointMake(self.contentStartPoint.x/self.contentBGImageView.frame.size.width, 0.0);[self resetAnChorPoint:self.contentBGImageView anchorPoint:anchorPoint];self.contentBGImageView.transform CGAffineTransformMakeScale(0.1, 0.1);[UIView animateWithDuration:0.25 animations:^{self.contentBGImageView.transform CGAffineTransformMakeScale(1.0, 1.0);self.contentBGImageView.alpha 1.0;} completion:^(BOOL finished) {}];
}隐藏菜单
- (void)dismissOption {[UIView animateWithDuration:0.25 animations:^{self.contentBGImageView.transform CGAffineTransformMakeScale(0.1, 0.1);self.contentBGImageView.alpha 0.0;} completion:^(BOOL finished) {self.hidden YES;[self removeFromSuperview];}];
}五、菜单完整代码
菜单完整代码如下
INNoteZoneOptionView.h
#import UIKit/UIKit.h/**元素的item*/
typedef void(^OptionTouchBlock)(void);
interface INNoteZoneOptionItem : NSObjectproperty (nonatomic, strong) UIImage *iconImage;
property (nonatomic, strong) NSString *title;
property (nonatomic, copy) OptionTouchBlock block;end/**按钮控件*/
interface INNoteZoneOptionButton : UIControlproperty (nonatomic, strong) UIImage *iconImage;
property (nonatomic, strong) NSString *title;
property (nonatomic, assign) BOOL showLine;
property (nonatomic, strong) INNoteZoneOptionItem *item;end/**点击➕号的选项操作*/
interface INNoteZoneOptionView : UIView- (instancetype)initWithFrame:(CGRect)frame anchorPoint:(CGPoint)anchorPoint items:(NSArray *)items;- (void)showOption;- (void)dismissOption;endINNoteZoneOptionView.m
#import INNoteZoneOptionView.h
#import UIColorAddition.h
#import UIImageViewWebCache.h
#import UIImageYYAdd.h
#import INNoteZoneOptionMaskView.h#define KCP 3.1415926static CGFloat kOpContentWidth 130.0;
static CGFloat kOpItemHeight 50.0;static CGFloat kOpIconSize 16.0;
static CGFloat kOpMidPadding 10.0;
static CGFloat kAnchorHeight 5.0;static CGFloat kBtnMidPadding 15.0;static CGFloat kBtnPadding 2.0;
static CGFloat kLineHeight 1.0;/**元素的item*/
interface INNoteZoneOptionItem ()endimplementation INNoteZoneOptionItemend/**按钮控件*/
interface INNoteZoneOptionButton ()property (nonatomic, strong) UIImageView *bgImageView;
property (nonatomic, strong) UIImageView *iconImageView;
property (nonatomic, strong) UILabel *titleLabel;
property (nonatomic, strong) UIImageView *lineImageView;endimplementation INNoteZoneOptionButton- (instancetype)initWithFrame:(CGRect)frame
{self [super initWithFrame:frame];if (self) {[self addSubview:self.bgImageView];[self.bgImageView addSubview:self.iconImageView];[self.bgImageView addSubview:self.titleLabel];[self.bgImageView addSubview:self.lineImageView];self.showLine NO;}return self;
}- (void)layoutSubviews {[super layoutSubviews];self.bgImageView.frame self.bounds;self.iconImageView.frame CGRectMake(kBtnMidPadding, (CGRectGetHeight(self.bounds) - kOpIconSize)/2, kOpIconSize, kOpIconSize);self.titleLabel.frame CGRectMake(CGRectGetMaxX(self.iconImageView.frame) kBtnMidPadding, 0.0, CGRectGetWidth(self.bgImageView.frame) - (CGRectGetMaxX(self.iconImageView.frame) kBtnMidPadding*2), CGRectGetHeight(self.bounds));self.lineImageView.frame CGRectMake(0.0, CGRectGetHeight(self.bgImageView.frame) - kLineHeight, CGRectGetWidth(self.bgImageView.frame), kLineHeight);
}- (void)setIconImage:(UIImage *)iconImage {_iconImage iconImage;self.iconImageView.image iconImage;[self setNeedsLayout];
}- (void)setTitle:(NSString *)title {_title (title?title:);self.titleLabel.text _title;[self setNeedsLayout];
}- (void)setShowLine:(BOOL)showLine {_showLine showLine;self.lineImageView.hidden !showLine;[self setNeedsLayout];
}- (void)setHighlighted:(BOOL)highlighted {[super setHighlighted:highlighted];if (highlighted) {self.bgImageView.backgroundColor [UIColor colorWithHexString:f4f4f4];} else {self.bgImageView.backgroundColor [UIColor whiteColor];}
}#pragma mark - SETTER/GETTER
- (UIImageView *)iconImageView {if (!_iconImageView) {_iconImageView [[UIImageView alloc] initWithFrame:CGRectZero];_iconImageView.contentMode UIViewContentModeScaleAspectFit;}return _iconImageView;
}- (UILabel *)titleLabel {if (!_titleLabel) {_titleLabel [[UILabel alloc] initWithFrame:CGRectZero];_titleLabel.font [UIFont boldSystemFontOfSize:14];_titleLabel.textColor [UIColor colorWithHexString:131619];_titleLabel.backgroundColor [UIColor clearColor];}return _titleLabel;
}- (UIImageView *)bgImageView {if (!_bgImageView) {_bgImageView [[UIImageView alloc] initWithFrame:CGRectZero];_bgImageView.backgroundColor [UIColor whiteColor];_bgImageView.layer.cornerRadius 2.0;_bgImageView.layer.masksToBounds YES;}return _bgImageView;
}- (UIImageView *)lineImageView {if (!_lineImageView) {_lineImageView [[UIImageView alloc] initWithFrame:CGRectZero];_lineImageView.backgroundColor [UIColor colorWithHexString:f1f1f1];}return _lineImageView;
}end/**点击➕号的选项操作*/
interface INNoteZoneOptionView ()INNoteZoneOptionMaskViewDelegateproperty (nonatomic, strong) INNoteZoneOptionMaskView *maskBGView;
property (nonatomic, strong) UIImageView *contentBGImageView;
property (nonatomic, strong) CAShapeLayer *shapeLayer;
property (nonatomic, strong) UIBezierPath *path;property (nonatomic) CGPoint anchorPoint;
property (nonatomic) CGPoint contentStartPoint;
property (nonatomic, strong) NSArray *items;endimplementation INNoteZoneOptionView- (instancetype)initWithFrame:(CGRect)frame anchorPoint:(CGPoint)anchorPoint items:(NSArray *)items {self [super initWithFrame:frame];if (self) {self.anchorPoint anchorPoint;self.items items;[self addSubview:self.maskBGView];[self addSubview:self.contentBGImageView];[self.contentBGImageView.layer addSublayer:self.shapeLayer];[[UIApplication sharedApplication].keyWindow addSubview:self];self.frame [UIScreen mainScreen].bounds;self.hidden YES;[self layoutOptionSubviews];[self configContentPoint];[self drawShapeLayer];[self setupOptionButtons];}return self;
}- (void)configContentPoint {CGFloat scale self.anchorPoint.x/self.frame.size.width;CGFloat contentWidth CGRectGetWidth(self.contentBGImageView.frame);self.contentStartPoint CGPointMake(scale*contentWidth - kOpMidPadding, 0.0);
}- (void)layoutOptionSubviews {self.maskBGView.frame self.bounds;self.contentBGImageView.frame CGRectMake(CGRectGetWidth(self.bounds) - kOpContentWidth - kOpMidPadding, self.anchorPoint.y, kOpContentWidth, self.items.count*kOpItemHeight kAnchorHeight 2*kBtnPadding);self.shapeLayer.frame self.contentBGImageView.bounds;
}#pragma mark - Setup Buttons
- (void)setupOptionButtons {NSInteger index 0;for (INNoteZoneOptionItem *item in self.items) {INNoteZoneOptionButton *button [[INNoteZoneOptionButton alloc] initWithFrame:CGRectZero];button.frame CGRectMake(kBtnPadding, kBtnPadding kAnchorHeight index*kOpItemHeight, CGRectGetWidth(self.contentBGImageView.frame) - 2*kBtnPadding, kOpItemHeight);button.iconImage item.iconImage;button.title item.title;button.item item;[self.contentBGImageView addSubview:button];[button addTarget:self action:selector(optionButtonAction:) forControlEvents:UIControlEventTouchUpInside];button.showLine YES;if (index self.items.count - 1) {button.showLine NO;}index;}
}- (void)optionButtonAction:(INNoteZoneOptionButton *)button {NSLog(点击栏目);if (button.item button.item.block) {button.item.block();}
}#pragma mark - Show AND Dismiss
- (void)showOption {self.hidden NO;CGPoint anchorPoint CGPointMake(self.contentStartPoint.x/self.contentBGImageView.frame.size.width, 0.0);[self resetAnChorPoint:self.contentBGImageView anchorPoint:anchorPoint];self.contentBGImageView.transform CGAffineTransformMakeScale(0.1, 0.1);[UIView animateWithDuration:0.25 animations:^{self.contentBGImageView.transform CGAffineTransformMakeScale(1.0, 1.0);self.contentBGImageView.alpha 1.0;} completion:^(BOOL finished) {}];
}- (void)dismissOption {[UIView animateWithDuration:0.25 animations:^{self.contentBGImageView.transform CGAffineTransformMakeScale(0.1, 0.1);self.contentBGImageView.alpha 0.0;} completion:^(BOOL finished) {self.hidden YES;[self removeFromSuperview];}];
}#pragma mark - ResetAnChorPoint
/**设置动画图钉位置param view subView*/
- (void)resetAnChorPoint:(UIView *)view anchorPoint:(CGPoint)anchorPoint {CGPoint oldAnchorPoint view.layer.anchorPoint;view.layer.anchorPoint anchorPoint;[view.layer setPosition:CGPointMake(view.layer.position.x view.layer.bounds.size.width * (view.layer.anchorPoint.x - oldAnchorPoint.x), view.layer.position.y view.layer.bounds.size.height * (view.layer.anchorPoint.y - oldAnchorPoint.y))];
}#pragma mark - INNoteZoneOptionMaskViewDelegate
- (void)optionMaskTouched {[self dismissOption];
}#pragma mark - SETTER/GETTER
- (INNoteZoneOptionMaskView *)maskBGView {if (!_maskBGView) {_maskBGView [[INNoteZoneOptionMaskView alloc] initWithFrame:CGRectZero];_maskBGView.backgroundColor [UIColor clearColor];_maskBGView.userInteractionEnabled YES;_maskBGView.maskDelegate self;}return _maskBGView;
}- (UIImageView *)contentBGImageView {if (!_contentBGImageView) {_contentBGImageView [[UIImageView alloc] initWithFrame:CGRectZero];_contentBGImageView.userInteractionEnabled YES;_contentBGImageView.backgroundColor [UIColor clearColor];}return _contentBGImageView;
}- (CAShapeLayer *)shapeLayer {if (!_shapeLayer) {_shapeLayer [CAShapeLayer layer];_shapeLayer.fillColor [UIColor whiteColor].CGColor;//设置线条的宽度和颜色_shapeLayer.lineWidth 1.0f;_shapeLayer.strokeColor [UIColor colorWithHexString:9bb9ef alpha:0.55].CGColor;_shapeLayer.shadowColor [UIColor colorWithHexString:9bb9ef].CGColor;_shapeLayer.shadowOffset CGSizeMake(-3, 3);_shapeLayer.shadowOpacity 0.3;_shapeLayer.shadowRadius 3.0;}return _shapeLayer;
}#pragma mark - DrawShapeLayer
- (void)drawShapeLayer {CGFloat startPointX self.contentStartPoint.x;CGFloat startPointY self.contentStartPoint.y;CGFloat width CGRectGetWidth(self.contentBGImageView.frame);CGFloat height CGRectGetHeight(self.contentBGImageView.frame);self.path [UIBezierPath bezierPath]; // 创建路径[self.path moveToPoint:CGPointMake(startPointX, startPointY)]; // 设置起始点[self.path addLineToPoint:CGPointMake(startPointX 5.0, kAnchorHeight)];[self.path addLineToPoint:CGPointMake(width - 5.0, kAnchorHeight)];[self.path addArcWithCenter:CGPointMake(width - 5.0, kAnchorHeight 5.0) radius:5 startAngle:KCP*3/2 endAngle:2*KCP clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(width, height - 5.0)];[self.path addArcWithCenter:CGPointMake(width - 5.0, height - 5.0) radius:5 startAngle:0 endAngle:KCP/2 clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(5, height)];[self.path addArcWithCenter:CGPointMake(5.0, height-5.0) radius:5 startAngle:KCP/2 endAngle:KCP clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(0.0, kAnchorHeight 5.0)];[self.path addArcWithCenter:CGPointMake(5, kAnchorHeight 5) radius:5 startAngle:KCP endAngle:KCP*3/2 clockwise:YES]; // 绘制一个圆弧[self.path addLineToPoint:CGPointMake(startPointX - 5.0, kAnchorHeight)];[self.path addLineToPoint:CGPointMake(startPointX, startPointY)];self.path.lineWidth 2.f;self.path.lineCapStyle kCGLineCapRound;self.path.lineJoinStyle kCGLineCapRound;[self.path closePath]; // 封闭未形成闭环的路径UIGraphicsBeginImageContext(self.contentBGImageView.bounds.size);[self.path stroke];UIGraphicsEndImageContext();self.shapeLayer.path self.path.CGPath;
}end六、使用显示下拉菜单
使用显示下拉菜单代码根据anchorPoint确定显示的箭头位置
#pragma mark - INNoteZoneNavbarViewDelegate
- (void)addButtonDidAction:(UIButton *)button {CGRect btnRect [button convertRect:button.bounds toView:[UIApplication sharedApplication].keyWindow];__weak typeof(self) weakSelf self;INNoteZoneOptionItem *postItem [[INNoteZoneOptionItem alloc] init];postItem.iconImage [UIImage imageNamed:ic_op_editpost];postItem.title 发布帖子;postItem.block ^{NSLog(发布帖子);};INNoteZoneOptionItem *scanItem [[INNoteZoneOptionItem alloc] init];scanItem.iconImage [UIImage imageNamed:ic_op_scan];scanItem.title 扫一扫;scanItem.block ^{NSLog(扫一扫);};INNoteZoneOptionItem *calItem [[INNoteZoneOptionItem alloc] init];calItem.iconImage [UIImage imageNamed:ic_op_cal];calItem.title 日历;calItem.block ^{NSLog(日历);};INNoteZoneOptionItem *pubWordItem [[INNoteZoneOptionItem alloc] init];pubWordItem.iconImage [UIImage imageNamed:ic_op_edit];pubWordItem.title 发布美句;pubWordItem.block ^{NSLog(发布美句);};INNoteZoneOptionView *optionView [[INNoteZoneOptionView alloc] initWithFrame:CGRectZero anchorPoint:CGPointMake(CGRectGetMidX(btnRect), CGRectGetMaxY(btnRect)) items:[postItem,scanItem,calItem,pubWordItem]];[optionView showOption];
}七、小结
iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 学习记录每天不停进步。