Using UIScrollView to realize the hexagonal picture browsing effect

The beginning of nonsense: using CATransform3D graphics transformation and some methods of UIScrollView to achieve a hexagonal picture browsing effect

1. Effect display

Screen recording 2022-07-16 4.29.03 pm 4.29.03.gif

Second, the realization principle

1. Add six side views of the hexagonal prism on a base View .

image.png

2. Adjust the rotation angle and z - axis value of each side of the hexagonal prism .

image.png

3. The base View is placed on the UIScrollView , and the coordinate x value of the base View and the rotation angle with the y -axis are set by monitoring the sliding of the UIScrollView .

3. Code

Create PhotoDrumBrowseView picture browsing class view

#import "PhotoDrumBrowseView.h"

@interface PhotoDrumBrowseView()<UIScrollViewDelegate>
@property(nonatomic,strong) UIScrollView * baseScrollView;
@property(nonatomic,strong) UIView * baseView;
@property(nonatomic,assign) CGRect originalBaseViewFrame;

@end

@implementation PhotoDrumBrowseView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self createUI];
        [self addDrumBrowseImageView];
    }
    return self;
}

- (void)createUI{
    //滚动视图其实主要是用来通过位置偏移进行计算旋转的角度(通过偏移量与总宽度计算旋转角度与一周2π的比值)
    self.baseScrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
    self.baseScrollView.showsHorizontalScrollIndicator = NO;
    [self addSubview:self.baseScrollView];
    CGFloat cellWidth = self.frame.size.width * 5.0 / 6.0;
    CGFloat cellHeight = cellWidth / 0.618;
    //加载六棱柱六个面
    self.baseView = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width - cellWidth) / 2.0, (self.frame.size.height - cellHeight) * 1 / 3.0, cellWidth, cellHeight)];
    self.originalBaseViewFrame = self.baseView.frame;
    [self.baseScrollView addSubview:self.baseView];
}

//创建六棱柱面
- (void)addDrumBrowseImageView{
    int num = 6;
    //一些角度计算
    float radian = (M_PI * 2) / num;
    float cellWidth = self.baseView.frame.size.width / 2.0;
    float cellHeight = cellWidth / 0.618;
    //前后z轴偏移值
    float needBFOff = cellWidth * sin(radian);
    //左右x轴偏移值
    float needLROff = cellWidth / 2.0 * cos(radian) + cellWidth / 2.0;
    self.baseScrollView.contentSize = CGSizeMake(self.frame.size.width / 2.0 + self.baseView.frame.size.width * num, 0);
    self.baseScrollView.delegate = self;
    for (int i = 0; i < num; i ++) {
        UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake((self.baseView.frame.size.width - cellWidth) / 2.0, (self.baseView.frame.size.height - cellHeight) / 2.0, cellWidth, cellHeight)];
        imageView.contentMode = UIViewContentModeScaleAspectFill;
        imageView.clipsToBounds = YES;
        imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"fd%d",i % 3 + 1]];
        [self.baseView addSubview:imageView];
        switch (i) {
            case 0:
            {
                //前左
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, -needLROff, 0,needBFOff / 2.0);
                imageView.layer.transform = CATransform3DRotate(imageView.layer.transform,- radian, 0, 1, 0);
            }
                break;
            case 1:
            {
                //前
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, 0, 0, needBFOff);
            }
                break;
            case 2:
            {
                //前右
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, needLROff, 0,needBFOff / 2.0);
                imageView.layer.transform = CATransform3DRotate(imageView.layer.transform, radian, 0, 1, 0);
            }
                break;
            case 3:
            {
                //前右
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, needLROff, 0, - needBFOff / 2.0);
                imageView.layer.transform = CATransform3DRotate(imageView.layer.transform,- radian, 0, 1, 0);
            }
                break;
            case 4:
            {
                //后
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, 0, 0, - needBFOff);
            }
                break;
            case 5:
            {
                //后左
                imageView.layer.transform = CATransform3DTranslate(imageView.layer.transform, -needLROff, 0,- needBFOff / 2.0);
                imageView.layer.transform = CATransform3DRotate(imageView.layer.transform, radian, 0, 1, 0);
            }
                break;
            default:
                break;
        }
    }
    //同时设置六个面的透视参数
    CATransform3D transformPerspective = CATransform3DIdentity;
    transformPerspective.m34 = -1.0f/800;
    self.baseView.layer.sublayerTransform = transformPerspective;
}


#pragma mark - 滚动进行图形变换
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    float offset = CGRectGetMinX(self.originalBaseViewFrame);
    //通过偏移量计算应该绕y轴旋转的角度
    float persent = (scrollView.contentOffset.x - offset) / (scrollView.contentSize.width - offset);
    //修改基础视图的frame,保持相对位置不变
    self.baseView.frame = CGRectMake(self.originalBaseViewFrame.origin.x + scrollView.contentOffset.x, self.originalBaseViewFrame.origin.y, self.originalBaseViewFrame.size.width, self.originalBaseViewFrame.size.height);
    //进行y轴旋转
    CATransform3D transformR = CATransform3DMakeRotation(-(M_PI * 2) * persent, 0, 1, 0);
    CATransform3D transformPerspective = CATransform3DIdentity;
    transformPerspective.m34 = -1.0f/800;
    self.baseView.layer.sublayerTransform = CATransform3DConcat(transformR, transformPerspective);
}

@end

4. Summary and thinking

The simple hexagonal image browsing is completed. The complicated part is mainly to calculate the position of the six faces and the rotation angle of the y -axis. You can enrich the internal functions by modifying the view of the six faces. After the view is set by transform , the attribute value of its frame will also be modified, and it is also possible to extend some functions from it. For example, if there is a diamond-shaped button, is it possible to select the button along the x - axis and y -axis to obtain a diamond-shaped button, so that the click range of such a diamond-shaped button will be within it. The code is clumsy, don't laugh at the great god

Guess you like

Origin juejin.im/post/7120894621244194847