iOS开发之随意移动的按钮,固定x轴根据y轴移动

本文介绍了一个iOS开发中的需求,如何创建一个按钮,使其在Y轴上自由移动,保持X轴位置不变,并确保按钮在屏幕范围内。同时,当按钮被点击时,文字会显示并五秒后自动消失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:view需根据y轴移动,固定x轴,且滑动不超出屏幕,点击按钮后文字出现,五秒后自动消失



xib RabbitView



RabbitView.h

#import <UIKit/UIKit.h>

typedef void(^ClickRabbitBlock)();

typedef void(^PanGestureRecognizer)(UIPanGestureRecognizer *panGes);

@interface RabbitView : UIView

@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

@property (weak, nonatomic) IBOutlet UIImageView *backImage;

// 初始化view
+ (instancetype)initWithChickenView;

@property (nonatomic, copy) ClickRabbitBlock block;

@property (nonatomic, copy) PanGestureRecognizer panBlock;

@property (weak, nonatomic) IBOutlet UIButton *rabbitBut;

@property (nonatomic, assign) CGRect rabbitFrame;//记录移动后的frame

// 设置兔子的背景图与文字是隐藏还是显示
- (void)rabbitViewHidden:(BOOL)hidden frame:(CGRect)frame;

@end



RabbitView.m

#import "RabbitView.h"

@implementation RabbitView

- (void)awakeFromNib {

    [super awakeFromNib];

    // 这里给view添加一个手势
    // 我这里因为view也需要可移动所以加在了view上,只需要移动按钮的,可以直接将手势加在按钮上
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
    [self addGestureRecognizer:pan];

    // 因为背景图有颜色,不设置clear的话滑动到灰色区域会显示白边
    self.backgroundColor = [UIColor clearColor];
}

// 设置兔子的背景图与文字是隐藏还是显示
- (void)rabbitViewHidden:(BOOL)hidden frame:(CGRect)frame {

    // 隐藏文字与背景图
    if (hidden == YES) {

        self.backImage.hidden = YES;
        self.titleLabel.hidden = YES;
        
        // 过渡动画
        [UIView transitionWithView:self duration:0.8 options:UIViewAnimationOptionShowHideTransitionViews animations:^{

            // 更新界面的宽度
            [self mas_updateConstraints:^(MASConstraintMaker *make) {
                make.width.mas_equalTo(60);
            }];
        } completion:^(BOOL finished) {
        }];

    } else {

        // 显示背景图与文字
        self.backImage.hidden = NO;
        self.titleLabel.hidden = NO;

        // 过渡动画
        [UIView transitionWithView:self duration:0.8 options:UIViewAnimationOptionAllowAnimatedContent animations:^{

            // 更新界面的宽度
            [self mas_updateConstraints:^(MASConstraintMaker *make) {
                make.width.mas_equalTo(220);
            }];
        } completion:^(BOOL finished) {
        }];
    }
    

    // ******* 注意这里
    // 判断是否是初始位置,origin.y默认是0,如果没有移动过直接点击按钮,y会移动到顶部
    if (frame.origin.y != 0) {        

        // 设置更新宽度后origin.y的位置,如果此处不处理的话容易造成点击后回到初始y轴位置
        [self mas_updateConstraints:^(MASConstraintMaker *make) {
            make.top.mas_equalTo(frame.origin.y);
        }];
    }
}

- (void)panAction:(UIPanGestureRecognizer *)pan {
    
    if (self.panBlock) {
        self.panBlock(pan);
    }
}

- (IBAction)clickRabbitButtonAction:(id)sender {

    // 判断是背景图与文字隐藏还是显示,以防5秒执行未结束又开启下一次执行
    if (self.backImage.hidden == YES) {

        if (self.block) {
            self.block();
        }
    }
}

+ (instancetype)initWithChickenView {

    NSString *className = NSStringFromClass([self class]);
    UINib *nib = [UINib nibWithNibName:className bundle:nil];    
    return [nib instantiateWithOwner:nil options:nil].firstObject;
}

ViewController.m

@interface SearchViewController () 

@property (nonatomic, strong) RabbitView *rabbitView;

@property (nonatomic, strong) NSTimer *timer;

@end


@implementation SearchViewController

- (void)viewDidLoad {

    [super viewDidLoad];
    [self.view addSubview:self.rabbitView];
    [self.rabbitView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(-3);
        make.top.mas_equalTo(SCREEN_HEIGHT-100);
        make.width.mas_equalTo(60);
        make.height.mas_equalTo(65);
    }];

    [self clickWithRabbitView];
}

// 点击兔子视图
- (void)clickWithRabbitView {

    __weak typeof(self) weakSelf = self;

    // 点击兔子
    self.rabbitView.block = ^{

            // 显示
            [weakSelf.rabbitView rabbitViewHidden:NO frame:weakSelf.rabbitFrame];
            // 开启定时器
            [weakSelf addTimerWithClickRabbit];
    };


    // 移动兔子
    self.rabbitView.panBlock = ^(UIPanGestureRecognizer *panGes) {

        // x轴固定  判断y轴是否超出界面
        CGPoint translationPoint = [panGes translationInView:weakSelf.view];
        CGPoint center = panGes.view.center;

        //计算view本身的center y
        CGFloat centerY = weakSelf.rabbitView.bounds.size.height / 2;

        //计算view顶部的偏移量 20是statusbar高度
        CGFloat topCenterY = centerY + 20;

        //计算view底部的偏移量
        CGFloat bottomCenterY = SCREEN_HEIGHT - centerY;

        //计算view center x 的偏移量  固定x轴(-3是因为为了背景图的自适应,正常计算不用-3)
        CGFloat centerX = weakSelf.rabbitView.bounds.size.width / 2 - 3;

        // 当现在的偏移量大于顶部偏移量时,根据现在的偏移量移动
        if (center.y >= topCenterY) {
            panGes.view.center = CGPointMake(centerX, center.y + translationPoint.y);
            [panGes setTranslation:CGPointZero inView:weakSelf.view];
        } else {
            // 当偏移量小于顶部偏移量时,根据最顶端偏移量固定
            panGes.view.center = CGPointMake(centerX, topCenterY);
            [panGes setTranslation:CGPointZero inView:weakSelf.view];
        }

        // 当现在的偏移量大于底部偏移量时,根据最底端偏移量固定
        if (center.y > bottomCenterY) {
            panGes.view.center = CGPointMake(centerX, bottomCenterY);
            [panGes setTranslation:CGPointZero inView:weakSelf.view];
        }

        // 记录移动后此时的frame
        weakSelf.rabbitFrame = panGes.view.frame;
    };
}

// 五秒后执行定时器,隐藏兔子
- (void)fiveLaterAction {

    [self.rabbitView rabbitViewHidden:YES frame:self.rabbitFrame];
     [_timer invalidate];
      _timer = nil;
}



// 开启定时器
- (void)addTimerWithClickRabbit {

    // 五秒后隐藏
NSTimer*timer=[NSTimer timerWithTimeInterval:5 target:self selector:@selector(fiveLaterAction) userInfo:nil repeats:NO];
    _timer = timer;
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}


//初始化view
- (RabbitView *)rabbitView {

    if (!_rabbitView) {
        _rabbitView = [RabbitView initWithChickenView];
        _rabbitView.backImage.hidden = YES;
        _rabbitView.titleLabel.hidden = YES;
    }

    return _rabbitView;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值