需求 - 5 - 悬浮框 - 1
来源:互联网 发布:信息技术软件介绍ppt 编辑:程序博客网 时间:2024/05/17 04:14
用过啥啥助手的都对一个悬浮球有印象,你可以任意拖拽这个悬浮窗口,点击它会展开很多功能菜单。
这里给出一个用传统setFrame的方法实现的例子,效果如下:
#import <UIKit/UIKit.h>@interface SuspensionFrameController : UIViewController@property (nonatomic, strong) UIView* flowMenu;//悬浮按钮@property (nonatomic, strong) UIButton* flowButton;//菜单栏@property (nonatomic, assign) BOOL isFlowButtonDismiss; //纪录悬浮框是否被隐藏@property (nonatomic, strong) NSTimer* hideFlowButtonTimer; //控制半隐藏的计时器@end
实现文件:
#import "QQChating.h"#import "SuspensionFrameController.h"@interface SuspensionFrameController ()@end@implementation SuspensionFrameController- (void)viewDidLoad{ [super viewDidLoad]; UIButton* showButton = [UIButton buttonWithType:UIButtonTypeCustom]; [showButton setFrame:CGRectMake(0, 0, 40, 40)]; [showButton setCenter:self.view.center]; [showButton setBackgroundColor:[UIColor blackColor]]; [showButton setTitle:@"点" forState:UIControlStateNormal]; [showButton addTarget:self action:@selector(showButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:showButton]; //默认悬浮框为半隐藏态 _isFlowButtonDismiss = YES; }- (void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning];}- (void)showButtonClicked:(id)sender{ //为什么判断nil,因为防止切换账号继续登录,切换账号之前已经存在这两个对象了 if (_flowButton == nil) { /** 菜单 **/ _flowMenu = [[UIView alloc] init]; [_flowMenu setBounds:CGRectMake(0, 0, 223, 24)]; //初始状态的时候高度定位中间 [_flowMenu setCenter:CGPointMake( VIEW_W(_flowMenu) * 0.5f + 18, VIEW_H(self.view) * 0.5f)]; [_flowMenu setAutoresizesSubviews:YES]; [_flowMenu setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin]; UIButton* fristButton = [UIButton buttonWithType:UIButtonTypeCustom]; [fristButton setFrame:CGRectMake(0, 0, 61, VIEW_H(_flowMenu))]; [fristButton setTitle:@"第一栏" forState:UIControlStateNormal]; [fristButton setTitleColor:UIColorWithRGB(0x88, 0x4a, 0x0e) forState:UIControlStateNormal]; [fristButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; [fristButton.titleLabel setFont:[UIFont systemFontOfSize:9]]; [fristButton setBackgroundImage:[UIImage imageNamed:@"firstC.png"] forState:UIControlStateNormal]; [fristButton setBackgroundImage:[UIImage imageNamed:@"firstC_seleted.png"] forState:UIControlStateSelected]; [fristButton addTarget:self action:@selector(fristButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; UIButton* secondButton = [UIButton buttonWithType:UIButtonTypeCustom]; [secondButton setFrame:CGRectMake(VIEW_W(fristButton), 0, 55, VIEW_H(_flowMenu))]; [secondButton setTitle:@"第二栏" forState:UIControlStateNormal]; [secondButton setTitleColor:UIColorWithRGB(0x88, 0x4a, 0x0e) forState:UIControlStateNormal]; [secondButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; [secondButton.titleLabel setFont:[UIFont systemFontOfSize:9]]; [secondButton setBackgroundImage:[UIImage imageNamed:@"secondC.png"] forState:UIControlStateNormal]; [secondButton setBackgroundImage:[UIImage imageNamed:@"secondC_seleted.png"] forState:UIControlStateSelected]; [secondButton addTarget:self action:@selector(secondButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; UIButton* thirdButton = [UIButton buttonWithType:UIButtonTypeCustom]; [thirdButton setFrame:CGRectMake(VIEW_TLX(secondButton) + VIEW_W(secondButton), 0, 55, VIEW_H(_flowMenu))]; [thirdButton setTitle:@"第三栏" forState:UIControlStateNormal]; [thirdButton setTitleColor:UIColorWithRGB(0x88, 0x4a, 0x0e) forState:UIControlStateNormal]; [thirdButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; [thirdButton.titleLabel setFont:[UIFont systemFontOfSize:9]]; [thirdButton setBackgroundImage:[UIImage imageNamed:@"thirdC.png"] forState:UIControlStateNormal]; [thirdButton setBackgroundImage:[UIImage imageNamed:@"thirdC_seleted.png"] forState:UIControlStateSelected]; [thirdButton addTarget:self action:@selector(thirdButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; UIButton* forthButton = [UIButton buttonWithType:UIButtonTypeCustom]; [forthButton setFrame:CGRectMake(VIEW_TLX(thirdButton) + VIEW_W(thirdButton), 0, 55, VIEW_H(_flowMenu))]; [forthButton setTitle:@"第四栏" forState:UIControlStateNormal]; [forthButton setTitleColor:UIColorWithRGB(0x88, 0x4a, 0x0e) forState:UIControlStateNormal]; [forthButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; [forthButton.titleLabel setFont:[UIFont systemFontOfSize:9]]; [forthButton setBackgroundImage:[UIImage imageNamed:@"forthC.png"] forState:UIControlStateNormal]; [forthButton setBackgroundImage:[UIImage imageNamed:@"forthC_seleted.png"] forState:UIControlStateSelected]; [forthButton addTarget:self action:@selector(forthButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [_flowMenu addSubview:fristButton]; [_flowMenu addSubview:secondButton]; [_flowMenu addSubview:thirdButton]; [_flowMenu addSubview:forthButton]; [self.view addSubview:_flowMenu]; //初始态隐藏 [_flowMenu setHidden:YES]; /** 处理洋葱头按钮 **/ _flowButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_flowButton setFrame:CGRectMake(0, 0, 36, 36)]; [_flowButton setCenter:CGPointMake(VIEW_W(_flowButton) * 0.5f, _flowMenu.center.y - 10)]; [_flowButton setAutoresizesSubviews:YES]; [_flowButton setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin]; [_flowButton setImage:[UIImage imageNamed:@"unselected.png"] forState:UIControlStateNormal]; [_flowButton setImage:[UIImage imageNamed:@"selected.png"] forState:UIControlStateSelected]; [_flowButton addTarget:self action:@selector(flowButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_flowButton]; UIPanGestureRecognizer* dragGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(flowButtonHandlePanGesture:)]; dragGesture.minimumNumberOfTouches = 1; dragGesture.maximumNumberOfTouches = 1; //在悬浮按钮上添加的手势操作 [_flowButton addGestureRecognizer:dragGesture]; } else { [self.view addSubview:_flowMenu]; [self.view addSubview:_flowButton]; }}#pragma mark - 菜单栏Button操作./** 四个菜单栏目 **/- (void)fristButtonClicked:(id)sender{ NSLog(@"fristButtonClicked !");}- (void)secondButtonClicked:(id)sender{ NSLog(@"secondButtonClicked !");}- (void)thirdButtonClicked:(id)sender{ NSLog(@"thirdButtonClicked !");}- (void)forthButtonClicked:(id)sender{ NSLog(@"forthButtonClicked !");}/** 悬浮按钮点击 **/- (void)flowButtonClicked:(id)sender{ NSLog(@"flowButton Clicked !"); if (_isFlowButtonDismiss) { //为啥这样判断,因为 : 悬浮框半隐藏的时候 if (_flowButton.center.x < VIEW_W(_flowButton.superview)) { [_flowButton setFrame:CGRectMake(0, VIEW_TLY(_flowButton), VIEW_W(_flowButton), VIEW_H(_flowButton))]; } else { [_flowButton setFrame:CGRectMake(VIEW_W(_flowButton.superview) - VIEW_W(_flowButton), VIEW_TLY(_flowButton), VIEW_W(_flowButton), VIEW_H(_flowButton))]; } _isFlowButtonDismiss = NO; } UIButton* button = (UIButton*)sender; [button setSelected:!button.isSelected]; if (button.isSelected) { CGPoint v; if (_flowButton.center.x >= VIEW_W(_flowButton.superview) * 0.5f) { v = CGPointMake(-( VIEW_W(_flowButton)*0.5f + VIEW_W(_flowMenu)*0.5f - 5 ), 5); } else { v = CGPointMake( VIEW_W(_flowButton)*0.5f + VIEW_W(_flowMenu)*0.5f - 5, 5); } [_flowMenu setCenter:cgpAdd(_flowButton.center, v)]; [_flowMenu setHidden:NO]; //展开菜单栏,并使计时器暂时失效 [_hideFlowButtonTimer invalidate]; } else { [_flowMenu setHidden:YES]; [self moveFlowButton]; }}/** 移动到半隐藏状态 **/- (void)moveFlowButton{ //每一次移动到半隐藏状态都将所有设置成初始状态,这样才统一 //这个问题遇到过几次了,这个实质上和重用出错也是一个道理,重用也是因为没有兼顾到新的变化嘛 //这个时候只要都把它们设置成原来的样子就像重用的时候重新设置一样 if (_isFlowButtonDismiss == NO) { _isFlowButtonDismiss = !_isFlowButtonDismiss; } if (_flowMenu.hidden == NO) { _flowMenu.hidden = !_flowMenu.hidden; } if (_flowButton.isSelected) { [_flowButton setSelected:!_flowButton.isSelected]; } //半隐藏屏幕边缘定时器 : NSTimer的初始化 , 要分别了解初始化的区别 //这里用了定时器来控制两个节奏: 首先通过下面的代码来使得悬浮框靠边,再触发定时器来半隐藏定时器 _hideFlowButtonTimer = [NSTimer timerWithTimeInterval:4.0f target:self selector:@selector(hideFlowButton) userInfo:nil repeats:NO]; float durationTime = VIEW_W(_flowButton.superview) * 0.00125f; //中线以左 : 左边 中线以右或者中线则靠右 if (_flowButton.center.x < VIEW_W(_flowButton.superview)*0.5f) { [UIView animateWithDuration:durationTime animations:^{ [_flowButton setCenter:CGPointMake(VIEW_W(_flowButton)*0.5f, _flowButton.center.y)]; [_flowMenu setCenter:CGPointMake(VIEW_W(_flowButton) + VIEW_W(_flowMenu)*0.5f, _flowMenu.center.y - 5)]; } completion:^(BOOL finished){ //结束靠边,半隐藏 [_hideFlowButtonTimer fire]; }]; } else { [UIView animateWithDuration:durationTime animations:^{ [_flowButton setCenter:CGPointMake(VIEW_W(_flowButton.superview) - VIEW_W(_flowButton)*0.5f + 0.1, _flowButton.center.y)]; [_flowMenu setCenter:CGPointMake(VIEW_W(_flowButton.superview) - VIEW_W(_flowButton) - VIEW_W(_flowMenu)*0.5f + 5, _flowMenu.center.y)]; } completion:^(BOOL finished){ [_hideFlowButtonTimer fire]; }]; } }/** 定时器控制的半隐藏悬浮框 **/- (void)hideFlowButton{ if (_flowButton.center.x < VIEW_W(_flowButton.superview)*0.5f) { [UIView animateWithDuration:0.5f animations:^{ [_flowButton setFrame:CGRectMake(-VIEW_W(_flowButton) + 10, VIEW_TLY(_flowButton), VIEW_W(_flowButton), VIEW_H(_flowButton))]; } completion:^(BOOL finished){ _isFlowButtonDismiss = YES; }]; } else { [UIView animateWithDuration:0.5f animations:^{ [_flowButton setFrame:CGRectMake(VIEW_W(_flowButton.superview) - 10, VIEW_TLY(_flowButton), VIEW_W(_flowButton), VIEW_H(_flowButton))]; } completion:^(BOOL finished){ _isFlowButtonDismiss = YES; }]; }}/** * 手势操作 - pan : 平移 * 手势操作实现原理 由 : begin changed end三个状态来实现 其中end 状态下如果没有弹出菜单栏直接调用 moveFlowButton 方法 , 如果弹出菜单栏则return , 单纯移动悬浮框 真正要理解这个,是要理解分次调用的时机,触发的情况,例如changed情况下如果变化很小,这个时候return没有操作 但是,还会是调用ended所以就可以看到这个时候先弹出全框再潜入半隐藏 */- (void)flowButtonHandlePanGesture:(UIPanGestureRecognizer* )gesture{ //这里的static用得实在是妙 , 因为这个拉拽是一个持续的过程,用static来保持最妥当 //因为通过移动按钮,所以origin这个点就是按钮的开始状态的坐标 static CGPoint originCenter; static CGPoint menuOriginCenter; if (gesture.state == UIGestureRecognizerStateBegan) { originCenter = gesture.view.center; menuOriginCenter = _flowMenu.center; } else if (gesture.state == UIGestureRecognizerStateChanged) { //注意到,手势是添加在悬浮button上,但是可以通过translationInview取到superview的坐标点 //这个是转化后移动变化的坐标点哦,既变化差,所以直接相加啦 , 思考一下, 为什么不用 [gesture translationInView:gesture.view] ? CGPoint nowCenter = cgpAdd(originCenter, [gesture translationInView:gesture.view.superview]); //移动很少,连半边脸都没有移够 //移动超多,到达了对面的边 //下面两个没啥必要的 if (nowCenter.x < VIEW_W(_flowButton)*0.5f || nowCenter.x > gesture.view.superview.bounds.size.width - VIEW_W(_flowButton)*0.5f || nowCenter.y < VIEW_H(_flowButton)*0.5f || nowCenter.y > gesture.view.superview.bounds.size.height - VIEW_H(_flowButton)*0.5f) { //符合条件的直接返回,但是不是说结束了哦,因为end状态还会触发函数执行 return; } //将悬浮框实时移动 gesture.view.center = nowCenter; CGPoint menuNowCenter = cgpAdd(menuOriginCenter, [gesture translationInView:gesture.view.superview]); [_flowMenu setCenter:menuNowCenter]; } else if (gesture.state == UIGestureRecognizerStateEnded) { if (_flowMenu.hidden == NO) { return; } [self moveFlowButton]; }}@end
0 0
- 需求 - 5 - 悬浮框 - 1
- 需求 - 5 - 悬浮框 - 2
- 需求 - 5 - 悬浮框 - 3
- WindowManager悬浮框1
- 悬浮框
- 悬浮框
- 悬浮框
- Android悬浮框应用--悬浮笔记
- [Javascript]右侧悬浮框
- 标题悬浮提示框
- Android 桌面悬浮框
- div悬浮提示框
- Android 桌面悬浮框
- Extjs添加悬浮框
- jquery悬浮提示框
- Android桌面悬浮框
- android 悬浮框
- 网站 图片 悬浮框
- 黑马程序员---Java异常和文件
- android ExpandableListView的下拉刷新实现
- 一个函数实现调节录音麦克风输入音量
- REST Vs SOAP,Soap 和 Rest 的区别
- const用法的总结
- 需求 - 5 - 悬浮框 - 1
- FFMpeg框架代码简介
- iOS屏幕旋转设置
- Jquery生成缩略图画廓
- pyenv python多版本共存
- git
- Mongodb VS Hbase
- CSS3 3D transform 秒懂
- 配置samba服务器