背景:
我不知道大伙们有没有遇到要做一个类似于小圆点的控件的需求,我在CocoaChina论坛上看别人说,这样的东西是会被拒审的,因为和系统的小圆点效果一样了。
管他呢,反正公司既然要求我做,那我做就是咯。
开发思路:
目前,我学习了两种方法。
一种较为简单,自定义一个UIImageView
来实现。把UIImageView
的交互打开,并且实现一个拖拽的手势,拖拽手势的方法里面实现对应效果即可。
另一种,稍微复杂一点点,直接用一个UIButton
来实现就好。和上面一样,也是实现一个拖拽的手势,只是拖拽手势里面算法复杂点。
两种都有各自不同的特点,看大家喜欢哪种,我比较喜欢第二种,因为第二种逼格更高点。
除了上述两种方法,还有一种方法:就是直接把控件添加到window里面去。你会发现,上述两种方法,不过都是加在根控制器的view里面去的。试想,如果当前是UIViewController还好说,如果是NavigationController呢?如果是TabBarController呢?如果是NavigationController或者是TabBarController的话,那么这个控件就会被遮挡的。怎么办?加在window上就好啦。
不过,如果项目中没有太大的硬性需求,最好不要加载window上,怪怪的。
方法一:
//
// ViewController.m
// SuspendDemo
//
// Created by HZhenF on 2017/9/12.
// Copyright © 2017年 HZhenF. All rights reserved.
//
#import "ViewController.h"
#import "SuspendImgV.h"
#import "OneViewController.h"
#define kScreenWidth [[UIScreen mainScreen] bounds].size.width
#define kScreenHeight [[UIScreen mainScreen] bounds].size.height
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
SuspendImgV * v = [[SuspendImgV alloc] initWithFrame:CGRectMake(100, 100, kItemWidth, kItemHeight) topMargin:66 btomMargin:44];
v.backgroundColor = [UIColor redColor];
v.image = [UIImage imageNamed:@"lufei.jpg"];
[self.view addSubview:v];
UIView * topV = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 66)];
topV.backgroundColor = [UIColor yellowColor];
UIView * centerV = [[UIView alloc] initWithFrame:CGRectMake(0, 66, kScreenWidth, kScreenHeight - 110)];
centerV.backgroundColor = [UIColor lightGrayColor];
UIView * btomV = [[UIView alloc] initWithFrame:CGRectMake(0, kScreenHeight - 44, kScreenWidth, 44)];
btomV.backgroundColor = [UIColor orangeColor];
[self.view addSubview:topV];
[self.view addSubview:centerV];
[self.view addSubview:btomV];
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 100, 100)];
[btn setTitle:@"点我" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
//将悬浮视图扔到最顶层
[self.view bringSubviewToFront:v];
}
-(void)btnAction
{
OneViewController *oneVC = [[OneViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:oneVC];
[self presentViewController:nav animated:YES completion:nil];
}
@end
//
// SuspendImgV.h
// SuspendDemo
//
// Created by HZhenF on 2017/9/12.
// Copyright © 2017年 HZhenF. All rights reserved.
//
#import <UIKit/UIKit.h>
#define kItemWidth 60
#define kItemHeight 60
@interface SuspendImgV : UIImageView
- (instancetype)initWithFrame:(CGRect)frame
topMargin:(CGFloat)top
btomMargin:(CGFloat)btom;
@end
//
// SuspendImgV.m
// SuspendDemo
//
// Created by HZhenF on 2017/9/12.
// Copyright © 2017年 HZhenF. All rights reserved.
//
#import "SuspendImgV.h"
typedef NS_ENUM(NSInteger, Position) {
PositionLeft = 0,
PositionRight = 1,
};
#define kHeight self.superview.frame.size.height
#define kWidth self.superview.frame.size.width
@interface SuspendImgV ()
@property (nonatomic, assign) Position position;
@property (nonatomic, assign) CGFloat topMargin;
@property (nonatomic, assign) CGFloat btomMargin;
@end
@implementation SuspendImgV
- (instancetype)initWithFrame:(CGRect)frame topMargin:(CGFloat)top btomMargin:(CGFloat)btom;
{
if (self = [super init]) {
self.frame = frame;
self.userInteractionEnabled = YES;
_topMargin = top;
_btomMargin = btom;
[self addGesture];
}
return self;
}
- (void)addGesture
{
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self addGestureRecognizer:pan];
}
- (void)configFrameWithAnimation:(BOOL)aniamtion
{
CGPoint p = self.frame.origin;
CGRect aimR = CGRectZero;
if (self.center.x < kWidth/2) {
aimR = CGRectMake(2, p.y, kItemWidth, kItemHeight);
_position = PositionLeft;
}else{
aimR = CGRectMake(kWidth - kItemWidth - 2, p.y, kItemWidth, kItemHeight);
_position = PositionRight;
}
if (aniamtion) {
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.frame = aimR;
} completion:nil];
}else{
self.frame = aimR;
}
}
- (void)panAction:(UIPanGestureRecognizer *)pan
{
if (pan.state == UIGestureRecognizerStateEnded
|| pan.state == UIGestureRecognizerStateCancelled){
//结束
[self configFrameWithAnimation:YES];
}
else {
//移动
//当然也可以相对于key window,只是self.superView的宽高和window不一致时,需要注意计算时的偏移量
CGPoint p = [pan locationInView:self.superview];
p.y = MAX(p.y, _topMargin + kItemHeight/2);
p.y = MIN(kHeight - _btomMargin - kItemHeight/2, p.y);
[UIView animateWithDuration:0.15 animations:^{
self.center = p;
}];
}
}
@end
方法二:
//
// ViewController.m
// SmallPoint
//
// Created by HZhenF on 2017/9/18.
// Copyright © 2017年 GZHYTechnology. All rights reserved.
//
#import "ViewController.h"
// 屏幕高度
#define susScreenH [UIScreen mainScreen].bounds.size.height
// 屏幕宽度
#define susScreenW [UIScreen mainScreen].bounds.size.width
//悬浮按钮宽高
#define kSuspendBtnWidth 100 * susScreenW / 375
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat X = 0;
CGFloat Y = 100;
CGFloat W = 100;
CGFloat H = 100;
UIButton *btnOne = [[UIButton alloc] initWithFrame:CGRectMake(X, Y, W, H)];
[btnOne setImage:[UIImage imageNamed:@"girl"] forState:UIControlStateNormal];
[self.view addSubview:btnOne];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[btnOne addGestureRecognizer:panGesture];
}
/**
拖拽事件
@param recognizer 当前拖拽的手势
*/
-(void)panAction:(UIPanGestureRecognizer *)recognizer
{
//移动状态
UIGestureRecognizerState recState = recognizer.state;
switch (recState) {
case UIGestureRecognizerStateBegan:
break;
case UIGestureRecognizerStateChanged:
{
UIViewController *viewVC = self;
CGPoint translation = [recognizer translationInView:viewVC.navigationController.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
}
break;
case UIGestureRecognizerStateEnded:
{
CGPoint stopPoint = CGPointMake(0, susScreenH / 2.0);
if (recognizer.view.center.x < susScreenW / 2.0)
{
if (recognizer.view.center.y <= susScreenH/2.0) {
//左上
if (recognizer.view.center.x >= recognizer.view.center.y) {
stopPoint = CGPointMake(recognizer.view.center.x, kSuspendBtnWidth/2.0);
}else{
stopPoint = CGPointMake(kSuspendBtnWidth/2.0, recognizer.view.center.y);
}
}
else{
//左下
if (recognizer.view.center.x >= susScreenH - recognizer.view.center.y) {
stopPoint = CGPointMake(recognizer.view.center.x, susScreenH - kSuspendBtnWidth/2.0);
}else{
stopPoint = CGPointMake(kSuspendBtnWidth/2.0, recognizer.view.center.y);
}
}
}
else{
if (recognizer.view.center.y <= susScreenH/2.0) {
//右上
if (susScreenW - recognizer.view.center.x >= recognizer.view.center.y) {
stopPoint = CGPointMake(recognizer.view.center.x, kSuspendBtnWidth/2.0);
}else{
stopPoint = CGPointMake(susScreenW - kSuspendBtnWidth/2.0, recognizer.view.center.y);
}
}else{
//右下
if (susScreenW - recognizer.view.center.x >= susScreenH - recognizer.view.center.y) {
stopPoint = CGPointMake(recognizer.view.center.x, susScreenH - kSuspendBtnWidth/2.0);
}else{
stopPoint = CGPointMake(susScreenW - kSuspendBtnWidth/2.0,recognizer.view.center.y);
}
}
}
if (stopPoint.x - kSuspendBtnWidth/2.0 <= 0) {
stopPoint = CGPointMake(kSuspendBtnWidth/2.0, stopPoint.y);
}
if (stopPoint.x + kSuspendBtnWidth/2.0 >= susScreenW) {
stopPoint = CGPointMake(susScreenW - kSuspendBtnWidth/2.0, stopPoint.y);
}
if (stopPoint.y - kSuspendBtnWidth/2.0 <= 0) {
stopPoint = CGPointMake(stopPoint.x, kSuspendBtnWidth/2.0);
}
if (stopPoint.y + kSuspendBtnWidth/2.0 >= susScreenH) {
stopPoint = CGPointMake(stopPoint.x, susScreenH - kSuspendBtnWidth/2.0);
}
[UIView animateWithDuration:0.5 animations:^{
recognizer.view.center = stopPoint;
}];
}
break;
default:
break;
}
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
@end