iOS仿美團(tuán)外賣餓了嗎App點(diǎn)餐動畫

效果圖

前言: 在這篇文章中你可以學(xué)到什么? Masonry布局, Block 以及動畫, 俗稱的懶加載. (想了解的看一看). 0.-

tableViewCell布局篇--為方便大家查看, 我會盡量貼出全部代碼

/**< typedef block >*/
typedef void(^btnPulsBlock)(NSInteger count, BOOL animated);
@interface XTFoodCell : UITableViewCell
@property (nonatomic, strong) UIImageView *foodImage;   // cyan
@property (nonatomic, strong) UILabel *nameLabel;       // orange
@property (nonatomic, strong) UILabel *priceLabel;      // gray
@property (nonatomic, strong) UIButton *btnMinus;       // black
@property (nonatomic, strong) UIButton *btnPlus;        // black
@property (nonatomic, strong) UILabel *orderCount;      // red
@property (nonatomic, copy)   btnPulsBlock block;       // block
@property (nonatomic, strong) UIImageView *animateView; // 購物車圖標(biāo)
@property (nonatomic, assign) NSInteger numCount;       // 計數(shù)器
@end

.m 實(shí)現(xiàn)篇

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self createSubviews];
    }
    return self;
}
- (void)createSubviews
{
    [self.contentView addSubview:self.foodImage];
    [self.contentView addSubview:self.nameLabel];
    [self.contentView addSubview:self.priceLabel];
    [self.contentView addSubview:self.btnMinus];
    [self.contentView addSubview:self.btnPlus];
    [self.contentView addSubview:self.orderCount];
}
- (UIImageView *)foodImage
{
    if (!_foodImage) {
        _foodImage = [[UIImageView alloc] init];
    }
    return _foodImage;
}
- (UILabel *)nameLabel
{
    if (!_nameLabel) {
        _nameLabel = [[UILabel alloc] init];
    }
    return _nameLabel;
}
- (UILabel *)priceLabel
{
    if (!_priceLabel) {
        _priceLabel = [[UILabel alloc] init];
    }
    return _priceLabel;
}
- (UIButton *)btnMinus
{
    if (!_btnMinus) {
        _btnMinus = [UIButton buttonWithType:UIButtonTypeCustom];
    }
    return _btnMinus;
}
- (UIButton *)btnPlus
{
    if (!_btnPlus) {
        _btnPlus = [UIButton buttonWithType:UIButtonTypeCustom];
    }
    return _btnPlus;
}
- (UILabel *)orderCount
{
    if (!_orderCount) {
        _orderCount = [[UILabel alloc] init];
    }
    return _orderCount;
}

UI布局篇--Masonry

- (void)layoutSubviews
{
    [super layoutSubviews];
    [_foodImage mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.contentView.mas_top).with.offset(5.0);
        make.left.equalTo(self.contentView.mas_left).with.offset(5.0);
        make.width.equalTo(@88.0);
        make.height.equalTo(@88.0);
    }];
    self.foodImage.backgroundColor = [UIColor cyanColor];
    
    [_nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.foodImage.mas_right).with.offset(5.0);
        make.top.equalTo(self.contentView.mas_top).with.offset(5.0);
        make.right.equalTo(self.contentView.mas_right).with.offset(-5.0);
        make.height.equalTo(@30);
    }];
    self.nameLabel.backgroundColor = [UIColor orangeColor];
    
    [_priceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(_nameLabel);
        make.width.equalTo(@50.0);
        make.height.equalTo(@30);
        make.bottom.equalTo(self.contentView.mas_bottom).with.offset(-5.0);
    }];
    self.priceLabel.backgroundColor = [UIColor lightGrayColor];
    
    [_btnMinus mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(_nameLabel);
        make.centerY.equalTo(self.contentView);
        make.width.height.mas_equalTo(CGSizeMake(25, 25));
    }];
    self.btnMinus.backgroundColor = [UIColor blackColor];
    
    [_orderCount mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(_btnMinus.mas_right).with.offset(10);
        make.centerY.equalTo(self.contentView);
        make.width.height.mas_equalTo(CGSizeMake(35, 25));
    }];
    self.orderCount.backgroundColor = [UIColor redColor];
    
    [self.btnPlus mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(_orderCount.mas_right).with.offset(10);
        make.centerY.equalTo(self.contentView);
        make.width.height.mas_equalTo(CGSizeMake(25, 25));
    }];
    self.btnPlus.backgroundColor = [UIColor blackColor];
    
    [_btnMinus setTitle:@"減" forState:UIControlStateNormal];
    [_btnMinus addTarget:self action:@selector(clickMin:) forControlEvents:UIControlEventTouchUpInside];
    _btnMinus.hidden = YES;

    [_btnPlus setTitle:@"加" forState:UIControlStateNormal];
    [_btnPlus addTarget:self action:@selector(clickPuls:) forControlEvents:UIControlEventTouchUpInside];   
}

btn點(diǎn)擊方法--

- (void)clickPuls:(UIButton *)btn
{
    self.numCount += 1;
    self.block(self.numCount, YES);
    [self showOrderNums:self.numCount];
    
}
- (void)clickMin:(UIButton *)btn
{
    self.numCount -= 1;
    self.block(self.numCount, NO);
    [self showOrderNums:self.numCount];
}

VC篇-- 這里給出cellForRowAtIndexPath中代碼

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    XTFoodCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
    
    // Block 回調(diào)
    __weak __typeof(&*cell) weakCell = cell;
    cell.block = ^(NSInteger nCount, BOOL boo){

        CGRect parentRect = [weakCell convertRect:weakCell.btnPlus.frame toView:self.view];
        
        if (boo) {
            // 這里是動畫開始的方法
            [self joinCartAnimationWithRect:parentRect];

        }
        else
        {

        }
    };
    return cell;
}
#pragma mark -加入購物車動畫
-(void) joinCartAnimationWithRect:(CGRect)rect
{
    _endPoint_x = 35;
    _endPoint_y = Screen_height - 35;
    
    CGFloat startX = rect.origin.x;
    CGFloat startY = rect.origin.y;
    
    _path= [UIBezierPath bezierPath];
    [_path moveToPoint:CGPointMake(startX, startY)];
    
    //三點(diǎn)曲線
    [_path addCurveToPoint:CGPointMake(_endPoint_x, _endPoint_y)
             controlPoint1:CGPointMake(startX, startY)
             controlPoint2:CGPointMake(startX - 180, startY - 200)];
    _dotLayer = [CALayer layer];
    _dotLayer.backgroundColor = [UIColor purpleColor].CGColor;
    _dotLayer.frame = CGRectMake(0, 0, 20, 20);
    _dotLayer.cornerRadius = 5;
    [self.view.layer addSublayer:_dotLayer];
    [self groupAnimation];   
}
#pragma mark - 組合動畫
-(void)groupAnimation
{
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.path = _path.CGPath;
    animation.rotationMode = kCAAnimationRotateAuto;
    
    CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"alpha"];
    alphaAnimation.duration = 0.5f;
    alphaAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    alphaAnimation.toValue = [NSNumber numberWithFloat:0.1];
    alphaAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    
    CAAnimationGroup *groups = [CAAnimationGroup animation];
    groups.animations = @[animation,alphaAnimation];
    groups.duration = 0.8f;
    groups.removedOnCompletion = NO;
    groups.fillMode = kCAFillModeForwards;
    groups.delegate = self;
    [groups setValue:@"groupsAnimation" forKey:@"animationName"];
    [_dotLayer addAnimation:groups forKey:nil];
    [self performSelector:@selector(removeFromLayer:) withObject:_dotLayer afterDelay:0.8f];   
}
- (void)removeFromLayer:(CALayer *)layerAnimation{
    
    [layerAnimation removeFromSuperlayer];
}

CAAnimationDelegate--

#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    
    if ([[anim valueForKey:@"animationName"]isEqualToString:@"groupsAnimation"]) {
        
        CABasicAnimation *shakeAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        shakeAnimation.duration = 0.25f;
        shakeAnimation.fromValue = [NSNumber numberWithFloat:0.9];
        shakeAnimation.toValue = [NSNumber numberWithFloat:1];
        shakeAnimation.autoreverses = YES;
        // 這里是下方的自定義View上面 放的btn. 自己隨便定義一個 0.- 
        [_shopCartView.btnBackImg.layer addAnimation:shakeAnimation forKey:nil];
    
}

基本就是全部代碼了. Demo下載
喜歡請點(diǎn)贊, 不喜歡請關(guān)注, 這樣你就可以找到我了. @.@
說明: 以下文章均在簡書平臺發(fā)布. 可點(diǎn)擊我的主頁查看全部. O.-
帶你系統(tǒng)學(xué)習(xí)GCD[一]
帶你系統(tǒng)學(xué)習(xí)GCD[二]
Swift版本仿網(wǎng)易云音樂播放音樂動畫效果
三分鐘教你把代碼托管到Github
Swift 很強(qiáng)大的圖表庫-Charts使用
Swift版仿簡書App淘寶App很友好彈出view效果

---------------------------------------
走心文章, 值得點(diǎn)贊 ---文/夏天然后
微博@夏天是個大人了 QQQ: 498143780
---------------------------------------
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子淀衣,更是在濱河造成了極大的恐慌,老刑警劉巖笛坦,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異叛买,居然都是意外死亡爽柒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門橄教,熙熙樓的掌柜王于貴愁眉苦臉地迎上來清寇,“玉大人,你說我怎么就攤上這事护蝶』蹋” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵持灰,是天一觀的道長盔夜。 經(jīng)常有香客問我,道長搅方,這世上最難降的妖魔是什么比吭? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任绽族,我火速辦了婚禮姨涡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吧慢。我一直安慰自己涛漂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布检诗。 她就那樣靜靜地躺著匈仗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逢慌。 梳的紋絲不亂的頭發(fā)上悠轩,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音攻泼,去河邊找鬼火架。 笑死,一個胖子當(dāng)著我的面吹牛忙菠,可吹牛的內(nèi)容都是我干的何鸡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼牛欢,長吁一口氣:“原來是場噩夢啊……” “哼骡男!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起傍睹,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤隔盛,失蹤者是張志新(化名)和其女友劉穎犹菱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吮炕,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡已亥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了来屠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虑椎。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俱笛,靈堂內(nèi)的尸體忽然破棺而出捆姜,到底是詐尸還是另有隱情,我是刑警寧澤迎膜,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布泥技,位于F島的核電站,受9級特大地震影響磕仅,放射性物質(zhì)發(fā)生泄漏珊豹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一榕订、第九天 我趴在偏房一處隱蔽的房頂上張望店茶。 院中可真熱鬧,春花似錦劫恒、人聲如沸贩幻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丛楚。三九已至,卻和暖如春憔辫,著一層夾襖步出監(jiān)牢的瞬間趣些,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工贰您, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坏平,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓枉圃,卻偏偏與公主長得像功茴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子孽亲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫坎穿、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,029評論 4 62
  • 邂逅木心孵延,是因了《從前慢》—— 記得早先少年時 大家誠誠懇懇 說一句 是一句 清早上火車站 長街黑暗無行人 賣豆?jié){...
    墨語花開時閱讀 1,190評論 1 5
  • 看過一些泛濫的諜戰(zhàn)劇吕漂,正義與邪惡的區(qū)分就是信仰問題,信仰堅定者的頭顱是高昂的尘应,即使死亡又如何惶凝,信仰不滅,精神長存犬钢。...
    獨(dú)一無二楊柳閱讀 456評論 0 0
  • 最近項(xiàng)目開發(fā)中遇到要復(fù)制Label上的文字的需求苍鲜,經(jīng)過查閱資料整理開發(fā)。 下面是自己借鑒網(wǎng)上各位大神的方法實(shí)現(xiàn)自己...
    短發(fā)控丶kk閱讀 1,654評論 2 0
  • 1玷犹、財富背后混滔,總有犯罪。-巴爾扎克 2歹颓、有個道理他早就弄清楚了坯屿,那就是你必須承受社會強(qiáng)加的侮辱,因?yàn)樗靼孜】福B最卑...
    弓亍閱讀 439評論 0 1