iOS: implement slider style gallery
This commit is contained in:
29
doric-iOS/Pod/Classes/Shader/DoricSliderLayout.h
Normal file
29
doric-iOS/Pod/Classes/Shader/DoricSliderLayout.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright [2023] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSliderNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by jingpeng.wang on 2023/6/13.
|
||||
//
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface DoricSliderLayout : UICollectionViewFlowLayout
|
||||
@property(nonatomic, assign) CGFloat galleryItemWidth;
|
||||
@property(nonatomic, assign) CGFloat galleryMinScale;
|
||||
@property(nonatomic, assign) CGFloat galleryMinAlpha;
|
||||
@end
|
||||
|
60
doric-iOS/Pod/Classes/Shader/DoricSliderLayout.m
Normal file
60
doric-iOS/Pod/Classes/Shader/DoricSliderLayout.m
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright [2023] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSliderNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by jingpeng.wang on 2023/6/13.
|
||||
//
|
||||
#import "DoricSliderLayout.h"
|
||||
|
||||
@implementation DoricSliderLayout
|
||||
|
||||
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
|
||||
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
|
||||
CGRect visitRect = {self.collectionView.contentOffset,self.collectionView.bounds.size};
|
||||
NSMutableArray *attributesCopy = [NSMutableArray array];
|
||||
for (UICollectionViewLayoutAttributes *attribute in attributes) {
|
||||
UICollectionViewLayoutAttributes *attributeCopy = [attribute copy];
|
||||
[attributesCopy addObject:attributeCopy];
|
||||
}
|
||||
|
||||
for (UICollectionViewLayoutAttributes *attribute in attributesCopy) {
|
||||
CGFloat distance = CGRectGetMidX(visitRect) - attribute.center.x;
|
||||
float diff = fabs(distance);
|
||||
CATransform3D scaleTransform = CATransform3DIdentity;
|
||||
|
||||
if (diff >= 0 && diff <= self.galleryItemWidth) {
|
||||
float scale = 1 - (1 - self.galleryMinScale) * (diff / self.galleryItemWidth);
|
||||
scaleTransform = CATransform3DMakeScale(scale, scale, scale);
|
||||
attribute.alpha = 1 - (1 - self.galleryMinAlpha) * (diff / self.galleryItemWidth);
|
||||
} else {
|
||||
float scale = self.galleryMinScale;
|
||||
scaleTransform = CATransform3DMakeScale(scale, scale, scale);
|
||||
attribute.alpha = self.galleryMinAlpha;
|
||||
}
|
||||
|
||||
attribute.transform3D = scaleTransform;
|
||||
}
|
||||
return attributesCopy;
|
||||
}
|
||||
|
||||
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#import "DoricSliderNode.h"
|
||||
#import "Doric.h"
|
||||
#import "DoricSlideItemNode.h"
|
||||
#import "DoricSliderLayout.h"
|
||||
|
||||
@interface DoricSliderViewCell : UICollectionViewCell
|
||||
@property(nonatomic, strong) DoricSlideItemNode *doricSlideItemNode;
|
||||
@@ -47,7 +48,11 @@ @interface DoricSliderNode () <UICollectionViewDataSource, UICollectionViewDeleg
|
||||
@property(nonatomic, strong) NSString *slideStyle;
|
||||
@property(nonatomic, assign) CGFloat minScale;
|
||||
@property(nonatomic, assign) CGFloat maxScale;
|
||||
@property(nonatomic, assign) CGFloat galleryMinScale;
|
||||
@property(nonatomic, assign) CGFloat galleryMinAlpha;
|
||||
@property(nonatomic, assign) CGFloat galleryItemWidth;
|
||||
@property(nonatomic, assign) BOOL scheduledLayout;
|
||||
@property (nonatomic, assign) NSInteger currentPage;
|
||||
@end
|
||||
|
||||
@interface DoricSliderView : UICollectionView
|
||||
@@ -75,7 +80,7 @@ - (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
}
|
||||
|
||||
- (UICollectionView *)build {
|
||||
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
DoricSliderLayout *flowLayout = [[DoricSliderLayout alloc] init];
|
||||
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
|
||||
return [[[DoricSliderView alloc] initWithFrame:CGRectZero
|
||||
collectionViewLayout:flowLayout]
|
||||
@@ -113,8 +118,21 @@ - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValu
|
||||
} else if ([@"slideStyle" isEqualToString:name]) {
|
||||
if ([prop isKindOfClass:NSDictionary.class]) {
|
||||
self.slideStyle = prop[@"type"];
|
||||
self.maxScale = [prop[@"maxScale"] floatValue];
|
||||
self.minScale = [prop[@"minScale"] floatValue];
|
||||
if ([self.slideStyle isEqualToString:@"zoomOut"]) {
|
||||
self.maxScale = [prop[@"maxScale"] floatValue];
|
||||
self.minScale = [prop[@"minScale"] floatValue];
|
||||
} else if([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
self.galleryMinScale = [prop[@"minScale"] floatValue];
|
||||
self.galleryMinAlpha = [prop[@"minAlpha"] floatValue];
|
||||
self.galleryItemWidth = [prop[@"itemWidth"] floatValue];
|
||||
self.view.pagingEnabled = NO;
|
||||
|
||||
DoricSliderLayout *layout = (DoricSliderLayout*)self.view.collectionViewLayout;
|
||||
layout.galleryItemWidth = self.galleryItemWidth;
|
||||
layout.galleryMinScale = self.galleryMinScale;
|
||||
layout.galleryMinAlpha = self.galleryMinAlpha;
|
||||
}
|
||||
|
||||
} else if ([prop isKindOfClass:NSString.class]) {
|
||||
self.slideStyle = prop;
|
||||
}
|
||||
@@ -161,11 +179,18 @@ - (void)afterBlended:(NSDictionary *)props {
|
||||
__strong typeof(_self) self = _self;
|
||||
[self.view reloadData];
|
||||
NSUInteger position = (self.loop ? 1 : 0) + self.slidePosition;
|
||||
if (self.view.width == 0) {
|
||||
float itemWidth;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
itemWidth = self.galleryItemWidth;
|
||||
} else {
|
||||
itemWidth = self.view.width;
|
||||
}
|
||||
|
||||
if (itemWidth == 0) {
|
||||
self.needResetScroll = true;
|
||||
} else {
|
||||
self.needResetScroll = false;
|
||||
[self.view setContentOffset:CGPointMake(position * self.view.width, self.view.contentOffset.y) animated:false];
|
||||
[self.view setContentOffset:CGPointMake(position * itemWidth, self.view.contentOffset.y) animated:false];
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -180,6 +205,12 @@ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSe
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.view.collectionViewLayout;
|
||||
int margin = (self.view.width - self.galleryItemWidth) / 2;
|
||||
layout.sectionInset = UIEdgeInsetsMake(0, margin, 0, margin);
|
||||
return CGSizeMake(self.galleryItemWidth, self.view.height);
|
||||
}
|
||||
return CGSizeMake(self.view.width, self.view.height);
|
||||
}
|
||||
|
||||
@@ -208,7 +239,12 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
|
||||
DoricSlideItemNode *node = cell.doricSlideItemNode;
|
||||
node.viewId = model[@"id"];
|
||||
[node blend:props];
|
||||
CGFloat maxWidth = collectionView.width;
|
||||
CGFloat maxWidth;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
maxWidth = self.galleryItemWidth;
|
||||
} else {
|
||||
maxWidth = collectionView.width;
|
||||
}
|
||||
if (collectionView.doricLayout.widthSpec == DoricLayoutFit) {
|
||||
maxWidth = [[UIScreen mainScreen] bounds].size.width;
|
||||
}
|
||||
@@ -322,7 +358,12 @@ - (void)blendSubNode:(NSDictionary *)subModel {
|
||||
if (viewNode) {
|
||||
CGSize originSize = viewNode.view.frame.size;
|
||||
[viewNode blend:subModel[@"props"]];
|
||||
[viewNode.view.doricLayout apply:CGSizeMake(self.view.width, self.view.height)];
|
||||
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
[viewNode.view.doricLayout apply:CGSizeMake(self.galleryItemWidth, self.view.height)];
|
||||
} else {
|
||||
[viewNode.view.doricLayout apply:CGSizeMake(self.view.width, self.view.height)];
|
||||
}
|
||||
[viewNode requestLayout];
|
||||
if (CGSizeEqualToSize(originSize, viewNode.view.frame.size)) {
|
||||
skipReload = YES;
|
||||
@@ -343,6 +384,39 @@ - (void)blendSubNode:(NSDictionary *)subModel {
|
||||
}];
|
||||
}
|
||||
|
||||
//paging by cell | paging with one cell at a time
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
{
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
CGFloat cellWidth = self.galleryItemWidth;
|
||||
self.currentPage = (scrollView.contentOffset.x - cellWidth / 2) / (cellWidth) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
|
||||
{
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
CGFloat cellWidth = self.galleryItemWidth;
|
||||
NSInteger page = (scrollView.contentOffset.x - cellWidth / 2) / (cellWidth) + 1;
|
||||
|
||||
if (velocity.x > 0) page++;
|
||||
if (velocity.x < 0) page--;
|
||||
page = MAX(page, 0);
|
||||
|
||||
NSInteger prePage = self.currentPage - 1;
|
||||
if(prePage > 0 && page < prePage){
|
||||
page = prePage;
|
||||
} else if (page > self.currentPage + 1){
|
||||
page = self.currentPage + 1;
|
||||
}
|
||||
|
||||
self.currentPage = page;
|
||||
|
||||
CGFloat newOffset = page * (cellWidth);
|
||||
targetContentOffset->x = newOffset;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if ([self.slideStyle isEqualToString:@"zoomOut"]) {
|
||||
CGFloat centerX = scrollView.width / 2.f;
|
||||
@@ -357,15 +431,28 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
NSUInteger pageIndex = (NSUInteger) (scrollView.contentOffset.x / scrollView.width);
|
||||
scrollView.contentOffset = CGPointMake(pageIndex * scrollView.width, scrollView.contentOffset.y);
|
||||
NSUInteger pageIndex;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
pageIndex = (NSUInteger) (scrollView.contentOffset.x / self.galleryItemWidth);
|
||||
scrollView.contentOffset = CGPointMake(pageIndex * self.galleryItemWidth, scrollView.contentOffset.y);
|
||||
} else {
|
||||
pageIndex = (NSUInteger) (scrollView.contentOffset.x / scrollView.width);
|
||||
scrollView.contentOffset = CGPointMake(pageIndex * scrollView.width, scrollView.contentOffset.y);
|
||||
}
|
||||
|
||||
|
||||
if (self.loop) {
|
||||
float itemWidth;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
itemWidth = self.galleryItemWidth;
|
||||
} else {
|
||||
itemWidth = self.view.width;
|
||||
}
|
||||
if (pageIndex == 0) {
|
||||
[self.view setContentOffset:CGPointMake(self.itemCount * self.view.width, self.view.contentOffset.y) animated:false];
|
||||
[self.view setContentOffset:CGPointMake(self.itemCount * itemWidth, self.view.contentOffset.y) animated:false];
|
||||
pageIndex = self.itemCount - 1;
|
||||
} else if (pageIndex == self.itemCount + 1) {
|
||||
[self.view setContentOffset:CGPointMake(1 * self.view.width, self.view.contentOffset.y) animated:false];
|
||||
[self.view setContentOffset:CGPointMake(1 * itemWidth, self.view.contentOffset.y) animated:false];
|
||||
pageIndex = 0;
|
||||
} else {
|
||||
pageIndex = pageIndex - 1;
|
||||
@@ -384,10 +471,17 @@ - (void)slidePage:(NSDictionary *)params withPromise:(DoricPromise *)promise {
|
||||
NSUInteger pageIndex = [params[@"page"] unsignedIntegerValue];
|
||||
BOOL smooth = [params[@"smooth"] boolValue];
|
||||
|
||||
if (self.loop) {
|
||||
[self.view setContentOffset:CGPointMake((pageIndex + 1) * self.view.width, self.view.contentOffset.y) animated:smooth];
|
||||
float itemWidth;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
itemWidth = self.galleryItemWidth;
|
||||
} else {
|
||||
[self.view setContentOffset:CGPointMake(pageIndex * self.view.width, self.view.contentOffset.y) animated:smooth];
|
||||
itemWidth = self.view.width;
|
||||
}
|
||||
|
||||
if (self.loop) {
|
||||
[self.view setContentOffset:CGPointMake((pageIndex + 1) * itemWidth, self.view.contentOffset.y) animated:smooth];
|
||||
} else {
|
||||
[self.view setContentOffset:CGPointMake(pageIndex * itemWidth, self.view.contentOffset.y) animated:smooth];
|
||||
}
|
||||
|
||||
[promise resolve:nil];
|
||||
@@ -398,7 +492,13 @@ - (void)slidePage:(NSDictionary *)params withPromise:(DoricPromise *)promise {
|
||||
}
|
||||
|
||||
- (NSNumber *)getSlidedPage {
|
||||
NSUInteger pageIndex = (NSUInteger) (self.view.contentOffset.x / self.view.width);
|
||||
NSUInteger pageIndex;
|
||||
if ([self.slideStyle isEqualToString:@"gallery"]) {
|
||||
pageIndex = (NSUInteger) (self.view.contentOffset.x / self.galleryItemWidth);
|
||||
} else {
|
||||
pageIndex = (NSUInteger) (self.view.contentOffset.x / self.view.width);
|
||||
}
|
||||
|
||||
if (self.loop) {
|
||||
return @(pageIndex - 1);
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user