使用iCarousel对项进行缩放

12

我尝试在我的项目中使用iCarousel,我需要实现像下面图片中的效果enter image description here

它应该完全按照iCarouselOptionFadeMin iCarouselOptionFadeMax iCarouselOptionFadeRange iCarouselOptionFadeMinAlpha 的方式工作。

- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value

我尝试创建一个与

- (CGFloat)alphaForItemWithOffset:(CGFloat)offset

我发现可以使用offset值来实现,但是对我来说事情并没有得到解决,有人能帮助我实现吗?

谢谢。

3个回答

30

您可以通过 iCarousel 的委托方法中的 iCarouselTypeCustom 类型来实现此操作。

- (CATransform3D)carousel:(iCarousel *)carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform

只需设置轮播图的类型(例如在轮播图视图控制器的 viewDidLoad 中):

self.carousel.type = iCarouselTypeCustom;

您可以按照自己的方式计算变换。我将对象放在一条双曲线上,并在它们远离中心时缩小它们。我认为这很像您的图像:

- (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;
}

结果如下图所示:result

你可以根据自己的喜好调整浮点常量。

如果要在圆周上移动物品并缩放它们,只需使用三角函数进行平移,然后旋转和缩放:

- (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;
} 

再次展示结果:

result2

您可以在carousel:valueForOption:withDefault:方法中调整间距和半径。

享受吧!:)


1
我尝试了一些不同的方法,而你的解决方案完美地为我工作。我得到了我想要的结果。 - Karthik
嗨,假设我想把它变成一个竖直的双曲线,我该怎么做呢?谢谢! - Gabriel Lim
1
iCarousel有一个名为vertical的属性,它设置了滚动手势的方向。此外,您需要在CATransform3DTranslate中切换xy参数,以便将项目沿y轴移动。 - burax

3

稍作修改,用SWIFT复制粘贴即可 ;) - 对我来说完美地工作

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;
}

0

我没有足够的声望来评论,所以我不得不作为回复再提出一个问题 :(

@burax 是否有可能在线性线上布局项目而不是双曲线,但保持调整大小?

谢谢,很抱歉这样问

编辑:通过随机尝试,我用这个实现了:

- (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;
}

可能有更好的方法,但我对转换还很陌生 :)


1
基本上,您只需要保留CATransform3DScale,并使用CATransform3DTranslate将项目移动offset在其X参数中。或者,可以查看我的其他答案:https://dev59.com/iXfZa4cB1Zd3GeqPTZje#19569605 - burax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接