圖片折疊效果
1.如何制作圖片折疊效果亦鳞?
`把一張圖片分成兩部分顯示思劳,上面一部分迅矛,下面一部分,折疊上面部分的內(nèi)容潜叛。`
2.如何把一張圖片分成兩部分顯示秽褒。
搞兩個(gè)控件,一個(gè)顯示上半部分威兜,一個(gè)顯示下半部分销斟,需要用到Layer(圖層)的一個(gè)屬性`contentsRect`,這個(gè)屬性是可以控制圖片顯示的尺寸,可以讓圖片只顯示上部分或者下部分椒舵,注意:`取值范圍是0~1`.
CGRectMake(0, 0, 1, 0.5)? : `表示顯示上半部分`
CGRectMake(0, 0.5, 1, 0.5) : `表示顯示下半部分`
3.如何快速的把兩部分拼接成一張完整的圖片蚂踊。
3.1 首先了解折疊,折疊其實(shí)就是旋轉(zhuǎn)笔宿,既然需要旋轉(zhuǎn)就需要明確錨點(diǎn)犁钟,因?yàn)槟J(rèn)都是繞著錨點(diǎn)旋轉(zhuǎn)的。
3.2 上部分內(nèi)容繞著底部中心旋轉(zhuǎn)泼橘,所以設(shè)置上部分的錨點(diǎn)為(0.5涝动,1)
3.3 錨點(diǎn)設(shè)置好了,就可以確定位置了.
3.4 可以把上下部分重合在一起炬灭,然后分別設(shè)置上下部分的錨點(diǎn)醋粟,
上部分的錨點(diǎn)為`(0.5,1)`,下部分的錨點(diǎn)為`(0.5昔穴,0)`,就能快速重疊了镰官。
4.如何折疊上部分內(nèi)容。
在拖動(dòng)視圖的時(shí)候吗货,旋轉(zhuǎn)上部分控件泳唠。修改`transform`屬性。
- 可以在上部分和下部分底部添加一個(gè)拖動(dòng)控件(`拖動(dòng)控件尺寸就是完整的圖片尺寸`)宙搬,給這個(gè)控件添加一個(gè)pan手勢(shì)笨腥,就能制造一個(gè)假象,拖動(dòng)控件的時(shí)候勇垛,折疊圖片脖母。
- 計(jì)算Y軸每偏移一點(diǎn),需要旋轉(zhuǎn)多少角度闲孤,假設(shè)完整圖片尺寸高度為200谆级,當(dāng)y = 200時(shí),上部分圖片應(yīng)該剛好旋轉(zhuǎn)180°讼积,因此`angle = offsetY? * M_PI / 200`;
- 上部分內(nèi)容應(yīng)該是繞著X軸旋轉(zhuǎn)肥照,`逆時(shí)針旋轉(zhuǎn)`,因此角度需要為負(fù)數(shù)勤众。
// 獲取手指偏移量
CGPoint transP = [sender translationInView:_containV];
// 初始化形變
CATransform3D transform3D = CATransform3DIdentity;
// 設(shè)置立體效果
transform3D.m34 = -1 / 1000.0;
// 計(jì)算折疊角度舆绎,因?yàn)樾枰鏁r(shí)針旋轉(zhuǎn),所以取反
CGFloat angle = -transP.y / 200.0 * M_PI;
_topView.layer.transform = CATransform3DRotate(transform3D, angle, 1, 0, 0);
- 為了讓折疊效果更加有效果们颜,更加具有立體感吕朵,可以給形變?cè)O(shè)置m34屬性,就能添加立體感窥突。
// 設(shè)置M34就有立體感(近大遠(yuǎn)小)努溃。 -1 / z ,z表示觀察者在z軸上的值,z越小,看起來(lái)離我們?cè)浇ǖ海瑬|西越大茅坛。
transform3D.m34 = -1 / 1000.0;
反彈效果
當(dāng)手指抬起的時(shí)候音半,應(yīng)該把折疊圖片還原则拷,其實(shí)就是把形變清空。
if (sender.state == UIGestureRecognizerStateEnded) { // 手指抬起
// 還原
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:3 options:UIViewAnimationOptionCurveEaseInOut animations:^{
_topView.layer.transform = CATransform3DIdentity;
} completion:nil];
}
陰影效果
當(dāng)折疊圖片的時(shí)候曹鸠,底部應(yīng)該有個(gè)陰影漸變過(guò)程煌茬。
-? 利用`CAGradientLayer`(漸變圖層)制作陰影效果,添加到底部視圖上彻桃,并且一開(kāi)始需要隱藏坛善,在拖動(dòng)的時(shí)候慢慢顯示出來(lái)。
-? 顏色應(yīng)是由`透明到黑色`漸變,表示陰影從無(wú)到有。
// 創(chuàng)建漸變圖層
CAGradientLayer *shadomLayer = [CAGradientLayer layer];
// 設(shè)置漸變顏色
shadomLayer.colors = @[(id)[UIColor clearColor],(id)[[UIColor blackColor] CGColor]];
shadomLayer.frame = _bottomView.bounds;
_shadomLayer = shadomLayer;
// 設(shè)置不透明度 0
shadomLayer.opacity = 0;
[_bottomView.layer addSublayer:shadomLayer];
-? 在拖動(dòng)的時(shí)候計(jì)算不透明度值眠屎,假設(shè)拖動(dòng)200剔交,陰影完全顯示,不透明度應(yīng)該為1改衩,因此 opacity = y軸偏移量 * 1 /? 200.0;
// 設(shè)置陰影不透明度
_shadomLayer.opacity = transP.y * 1 /? 200.0;
-? 在手指抬起的時(shí)候岖常,需要把陰影設(shè)置隱藏,不透明度為0葫督;
if (sender.state == UIGestureRecognizerStateEnded) { // 手指抬起
// 還原
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:3 options:UIViewAnimationOptionCurveEaseInOut animations:^{
_topView.layer.transform = CATransform3DIdentity;
// 還原陰影
_shadomLayer.opacity = 0;
} completion:nil];
}
----------------------------------------------------------
音量振動(dòng)條
如何實(shí)現(xiàn)竭鞍?
創(chuàng)建3個(gè)layer,按順序播放y軸縮放動(dòng)畫(huà)
?利用CAReplicatorLayer實(shí)現(xiàn)
1橄镜、什么是CAReplicatorLayer偎快?
一種可以復(fù)制自己子層的layer,并且復(fù)制出來(lái)的layer和原生子層有同樣的屬性,位置洽胶,形變晒夹,動(dòng)畫(huà)。
2姊氓、CAReplicatorLayer屬性
- `instanceCount`: 子層總數(shù)(包括原生子層)
- `instanceDelay`: 復(fù)制子層動(dòng)畫(huà)延遲時(shí)長(zhǎng)
- `instanceTransform`: 復(fù)制子層形變(不包括原生子層)惋戏,每個(gè)復(fù)制子層都是相對(duì)上一個(gè)。
- `instanceColor`: 子層顏色他膳,會(huì)和原生子層背景色沖突响逢,因此二者選其一設(shè)置。
- `instanceRedOffset棕孙、instanceGreenOffset舔亭、instanceBlueOffset、instanceAlphaOffset`: 顏色通道偏移量蟀俊,每個(gè)復(fù)制子層都是相對(duì)上一個(gè)的偏移量钦铺。
如果利用CAReplicatorLayer實(shí)現(xiàn)
1.首先創(chuàng)建復(fù)制layer,音樂(lè)振動(dòng)條layer添加到復(fù)制layer上,然后復(fù)制子層就好了肢预。
CAReplicatorLayer *layer = [CAReplicatorLayer layer];
layer.frame = CGRectMake(50, 50, 200, 200);
layer.backgroundColor = [UIColor lightGrayColor].CGColor;
[self.view.layer addSublayer:layer];
2.先創(chuàng)建一個(gè)音量振動(dòng)條矛洞,并且設(shè)置好動(dòng)畫(huà),動(dòng)畫(huà)是繞著底部縮放,設(shè)置錨點(diǎn)
CALayer *bar = [CALayer layer];
bar.backgroundColor = [UIColor redColor].CGColor;
bar.bounds = CGRectMake(0, 0, 30, 100);
bar.position = CGPointMake(15, 200);
bar.anchorPoint = CGPointMake(0.5, 1);
[layer addSublayer:bar];
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"transform.scale.y";
anim.toValue = @(0.1);
anim.autoreverses = YES;
anim.repeatCount = MAXFLOAT;
[bar addAnimation:anim forKey:nil];
3.復(fù)制子層
// 設(shè)置4個(gè)子層烫映,3個(gè)復(fù)制層
layer.instanceCount = 4;
// 設(shè)置復(fù)制子層的相對(duì)位置沼本,每個(gè)x軸相差40
layer.instanceTransform = CATransform3DMakeTranslation(40, 0, 0);
// 設(shè)置復(fù)制子層的延遲動(dòng)畫(huà)時(shí)長(zhǎng)
layer.instanceDelay = 0.3;
-------------------------------------------------------
活動(dòng)指示器
實(shí)現(xiàn)思路
1.創(chuàng)建復(fù)制圖層
CAReplicatorLayer *replicator = [CAReplicatorLayer layer];
replicator.frame = CGRectMake(50, 50, 200, 200);
replicator.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:replicator];
2.創(chuàng)建一個(gè)矩形圖層,設(shè)置縮放動(dòng)畫(huà)锭沟。
CALayer *indicator = [CALayer layer];
indicator.transform = CATransform3DMakeScale(0, 0, 0);
indicator.position = CGPointMake(100, 20);
indicator.bounds = CGRectMake(0, 0, 10, 10);
indicator.backgroundColor = [UIColor greenColor].CGColor;
[replicator addSublayer:indicator];
CGFloat durtion = 1;
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"transform.scale";
anim.fromValue = @1;
anim.toValue = @0.1;
anim.repeatCount = MAXFLOAT;
anim.duration = durtion;
[indicator addAnimation:anim forKey:nil];
3.復(fù)制矩形圖層抽兆,并且設(shè)置每個(gè)復(fù)制層的角度形變
int count = 10;
// 設(shè)置子層次數(shù)
replicator.instanceCount = count;
// 設(shè)置子層形變角度
CGFloat angle = M_PI * 2 / count;
replicator.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
4.設(shè)置復(fù)制動(dòng)畫(huà)延長(zhǎng)時(shí)間(需要保證第一個(gè)執(zhí)行完畢之后,繞一圈剛好又是從第一個(gè)執(zhí)行族淮,因此需要把動(dòng)畫(huà)時(shí)長(zhǎng)平均分給每個(gè)子層)
公式:延長(zhǎng)時(shí)間 = 動(dòng)畫(huà)時(shí)長(zhǎng) / 子層總數(shù)
假設(shè)有兩個(gè)圖層辫红,動(dòng)畫(huà)時(shí)間為1秒凭涂,延長(zhǎng)時(shí)間就為0.5秒。當(dāng)?shù)谝粋€(gè)動(dòng)畫(huà)執(zhí)行到一半的時(shí)候(0.5)贴妻,第二個(gè)開(kāi)始執(zhí)行切油。第二個(gè)執(zhí)行完
// 設(shè)置子層動(dòng)畫(huà)延長(zhǎng)時(shí)間
replicator.instanceDelay = durtion / count;
---------------------------------------------------------
粒子動(dòng)畫(huà)
效果:隨機(jī)繪制一條路徑,點(diǎn)擊開(kāi)始按鈕名惩,粒子動(dòng)畫(huà)
實(shí)現(xiàn)思路
1.搞個(gè)畫(huà)板繪制路徑白翻,自定義view
2.給自定義view添加pan手勢(shì),和創(chuàng)建復(fù)制圖層和圓形圖層绢片,只需要設(shè)置一次滤馍,在awakeFromNib方法中設(shè)置。
// 添加pan手勢(shì)
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
// 創(chuàng)建復(fù)制圖層
CAReplicatorLayer *repLayer = [CAReplicatorLayer layer];
repLayer.frame = self.bounds;
[self.layer addSublayer:repLayer];
// 創(chuàng)建粒子圖層
CALayer *layer = [CALayer layer];
layer.cornerRadius = 5;
layer.frame = CGRectMake(-100, 10, 10, 10);
layer.backgroundColor = [UIColor whiteColor].CGColor;
[repLayer addSublayer:layer];
_dotLayer = layer;
3.因?yàn)楹诵膭?dòng)畫(huà)只能設(shè)置一個(gè)路徑底循,因此只能創(chuàng)建一個(gè)路徑巢株,懶加載路徑。
- (UIBezierPath *)path
{
if (_path == nil) {
_path = [UIBezierPath bezierPath];
}
return _path;
}
4.在一開(kāi)始拖動(dòng)的時(shí)候熙涤,保存路徑起點(diǎn)阁苞,設(shè)置路徑起點(diǎn),拖動(dòng)的時(shí)候每次添加線到某個(gè)點(diǎn)祠挫。
CGPoint curP = [pan locationInView:self];
if (pan.state == UIGestureRecognizerStateBegan) {
_startP = curP;
[self.path moveToPoint:_startP];
}
[self.path addLineToPoint:curP];
[self setNeedsDisplay];
5.路徑繪制好了那槽,點(diǎn)擊開(kāi)始按鈕的時(shí)候,添加動(dòng)畫(huà)到圖層
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
anim.keyPath = @"position";
anim.duration = 4;
anim.path = self.path.CGPath;
anim.repeatCount = MAXFLOAT;
[_dotLayer addAnimation:anim forKey:@"anim"];
anim.delegate = self;
6.復(fù)制圖層
repLayer.instanceCount = 20;
repLayer.instanceDelay = 4 / 20.0;
// 設(shè)置子層顏色
repLayer.instanceColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:1].CGColor;
// 設(shè)置子層顏色綠色通道偏移量
repLayer.instanceGreenOffset = -0.03;
7.重繪
清空路徑等舔,重新繪制骚灸,移除圖層動(dòng)畫(huà)。
_path = nil;
[_dotLayer removeAnimationForKey:@"anim"];
[self setNeedsDisplay];
--------------------------------------------------------
倒影
實(shí)現(xiàn)思路:
1.用復(fù)制圖層實(shí)現(xiàn)慌植,搞個(gè)UIImageView展示圖片甚牲,然后復(fù)制UIImageView.
2.注意:`復(fù)制圖層只能復(fù)制子層,但是UIImageView只有一個(gè)主層蝶柿,并沒(méi)有子層丈钙,因此不能直接復(fù)制UIImageView`.
3.正確做法:應(yīng)該把UIImageView添加到一個(gè)UIView上,然后復(fù)制UIView的層交汤,就能復(fù)制UIImageView.
注意:`默認(rèn)A控件是B控件的子控件雏赦,那么A控件的層就是B控件的層的子層。`
4.但是有問(wèn)題芙扎,默認(rèn)UIView的層不是復(fù)制層星岗,我們想把UIView的層變成復(fù)制層,重寫(xiě)+layerClass方法纵顾。
+ (Class)layerClass
{
return [CAReplicatorLayer class];
}
5.倒影效果:就是就是把復(fù)制圖片旋轉(zhuǎn)180度伍茄,然后往下平移栋盹,最好先偏移在施逾,在旋轉(zhuǎn)敷矫。
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.v.layer;
layer.instanceCount = 2;
// 先Y軸偏移
CATransform3D transform =? CATransform3DMakeTranslation(0, self.v.bounds.size.height, 0);
// 在旋轉(zhuǎn)
transform = CATransform3DRotate(transform, M_PI, 1, 0, 0);
// 設(shè)置復(fù)制層的形變
layer.instanceTransform = transform;
// 設(shè)置顏色通道偏移量,相等上一個(gè)一點(diǎn)偏移量汉额,就是陰影效果
layer.instanceRedOffset = -0.1;
layer.instanceGreenOffset = -0.1;
layer.instanceBlueOffset = -0.1;
layer.instanceAlphaOffset = -0.1;
----------------------------------------------------------
QQ粘性效果
實(shí)現(xiàn)思路:
1.自定義大圓控件(UIButton)可以顯示背景圖片曹仗,和文字
2.讓大圓控件隨著手指移動(dòng)而移動(dòng)
- 注意不能根據(jù)形變修改大圓的位置,只能通過(guò)center蠕搜,因?yàn)槿潭夹枰玫街行狞c(diǎn)計(jì)算怎茫。
3.在拖動(dòng)的時(shí)候,添加一個(gè)小圓控件在原來(lái)大圓控件的位置
- 注意這個(gè)小圓控件并不會(huì)隨著手指移動(dòng)而移動(dòng)妓灌,因此應(yīng)該添加到父控件上
- 一開(kāi)始設(shè)置中心點(diǎn)和尺寸和大圓控件一樣轨蛤。
- 隨著大圓拖動(dòng),小圓半徑不斷減少虫埂,可以根據(jù)兩個(gè)圓心的距離祥山,隨便生成一段比例,隨著圓心距離增加掉伏,圓心半徑不斷減少缝呕。
// 計(jì)算小圓半徑:隨機(jī)搞個(gè)比例,隨著圓心距離增加斧散,圓心半徑不斷減少供常。
CGFloat smallRadius = _circleR2 - d / 10;
- 每次小圓改變,需要重新設(shè)置小圓的尺寸和圓角半徑鸡捐。
4.粘性效果
- 就是在兩圓之間繪制一個(gè)形變矩形栈暇,描述形變矩形路徑。
- `這里大致介紹下計(jì)算思路箍镜,不需要太糾結(jié)`
- 這里需要用到CAShapeLayer,可以根據(jù)一個(gè)路徑瞻鹏,生成一個(gè)圖層,展示出來(lái)鹿寨。把形變圖層添加到父控件并且顯示在小圓圖層下就OK了新博。因?yàn)樗杏?jì)算出來(lái)的點(diǎn),都是基于父控件脚草。
- `注意:這里不能用繪圖赫悄,因?yàn)槔L圖內(nèi)容只要超過(guò)當(dāng)前控件尺寸就不會(huì)顯示,但是當(dāng)前形變矩形必須顯示在控件之外`
5.粘性業(yè)務(wù)邏輯處理
- 當(dāng)圓心距離超過(guò)100馏慨,就不需要描述形變矩形(并且把之前的形變矩形移除父層)埂淮,小圓也需要隱藏。
- 沒(méi)有超過(guò)100写隶,則相反倔撞。
?6.手指停止拖動(dòng)業(yè)務(wù)邏輯
- 判斷下圓心是否超過(guò)100,超過(guò)就播放爆炸效果慕趴,添加個(gè)UIImageView在當(dāng)前控件上痪蝇,并且需要取消控制器view的自動(dòng)布局鄙陡。
// 取消Autoresizing轉(zhuǎn)自動(dòng)布局
self.view.translatesAutoresizingMaskIntoConstraints = NO;
- 沒(méi)有超過(guò),就還原躏啰。