可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was trying to use iCarousel for one my solutions, I need to achieve something like the image below
It should be exactly the way
iCarouselOptionFadeMin iCarouselOptionFadeMax iCarouselOptionFadeRange iCarouselOptionFadeMinAlpha works using
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
I tried to create a function exactly like
- (CGFloat)alphaForItemWithOffset:(CGFloat)offset
I discovered that it cane be done using offset values, but things are not working me, can any one can help me achieving this?
Thanks.
回答1:
You can do this via the iCarousel's iCarouselTypeCustom type in the delegate method
- (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform
Just set the type of the carousel (e.g. in viewDidLoad of the carousel's view controller):
self.carousel.type = iCarouselTypeCustom;
And calculate the transform as you like. I've laid the objects on a hyperbola, and shrink them in addition a bit as they move away from the center. That quite resembles your image, I think:
- (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform { const CGFloat offsetFactor = [self carousel:carousel valueForOption:iCarouselOptionSpacing withDefault:1.0f]*carousel.itemWidth; //The larger these values, as the items move away from the center ... //... the faster they move to the back const CGFloat zFactor = 150.0f; //... the faster they move to the bottom of the screen const CGFloat normalFactor = 50.0f; //... the faster they shrink const CGFloat shrinkFactor = 3.0f; //hyperbola CGFloat f = sqrtf(offset*offset+1)-1; transform = CATransform3DTranslate(transform, offset*offsetFactor, f*normalFactor, f*(-zFactor)); transform = CATransform3DScale(transform, 1/(f/shrinkFactor+1.0f), 1/(f/shrinkFactor+1.0f), 1.0); return transform; }
and the result:
you can adjust the float constants to your liking.
For moving items around a circle while scaling them just use goniometric functions for translation, then rotate and scale:
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value { if (option == iCarouselOptionSpacing) { return value * 2.0f; } if(option == iCarouselOptionVisibleItems) { return 11; } if(option == iCarouselOptionWrap) return YES; return value; } - (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform { const CGFloat radius = [self carousel:carousel valueForOption:iCarouselOptionRadius withDefault:200.0]; const CGFloat offsetFactor = [self carousel:carousel valueForOption:iCarouselOptionSpacing withDefault:1.0f]*carousel.itemWidth; const CGFloat angle = offset*offsetFactor/radius; //... the faster they shrink const CGFloat shrinkFactor = 2.0f; //hyperbola (now only for shrinking purposes) CGFloat f = sqrtf(offset*offset+1)-1; transform = CATransform3DTranslate(transform, radius*sinf(angle), radius*(1-cosf(angle)), 0.0); transform = CATransform3DRotate(transform, angle, 0, 0, 1); transform = CATransform3DScale(transform, 1/(f*shrinkFactor+1.0f), 1/(f*shrinkFactor+1.0f), 1.0); return transform; }
and again, the result:
you can adjust the spacing and the radius in the carousel:valueForOption:withDefault: method.
Enjoy! :)
回答2:
A little modified and in SWIFT to copy paste ;) - works perfekt for me
func carousel(carousel: iCarousel, valueForOption option: iCarouselOption, withDefault value: CGFloat) -> CGFloat { if option == iCarouselOption.Spacing { return value * 1.8 } return value } func carousel(carousel: iCarousel, itemTransformForOffset offset: CGFloat, baseTransform transform: CATransform3D) -> CATransform3D { let offsetFactor = self.carousel(carousel, valueForOption: iCarouselOption.Spacing, withDefault: 1) * carousel.itemWidth let zFactor: CGFloat = 150 let normalFactor: CGFloat = 0 let shrinkFactor: CGFloat = 1 let f = sqrt(offset*offset+1)-1 var transform = CATransform3DTranslate(transform, offset*offsetFactor, f*normalFactor, f*(-zFactor)); transform = CATransform3DScale(transform, 1/(f/shrinkFactor+1), 1/(f/shrinkFactor+1), 1); return transform; }
回答3:
I do not have enough reputation to comment so i have to ask a further question as a reply :(
@burax is it possible to layout items on linear line instead of a hyperbola but keep the resizing?
Regards, and sorry for asking like this
Edit : with random tries i achieved with this :
- (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform { const CGFloat radius = [self carousel:carousel valueForOption:iCarouselOptionRadius withDefault:5050.0]; const CGFloat offsetFactor = [self carousel:carousel valueForOption:iCarouselOptionSpacing withDefault:0.8f]*carousel.itemWidth; const CGFloat angle = offset*offsetFactor/radius; //... the faster they shrink const CGFloat shrinkFactor = 2.0f; //hyperbola (now only for shrinking purposes) CGFloat f = sqrtf(offset*offset+1)-1; transform = CATransform3DTranslate(transform, radius*sinf(angle), radius*(1-cosf(angle)), 0.0); transform = CATransform3DRotate(transform, angle, 0, 0, 1); transform = CATransform3DScale(transform, 1/(f*shrinkFactor+1.0f), 1/(f*shrinkFactor+1.0f), 1.0); return transform; }
there is probably a better way but i am new to transformations :)