封裝了一個使用UICollectionViewLayout 實現的吸附居左banner圖

首先查看效果圖
在這里插入圖片描述

實現的原理就是通過自定義UICollectionView layout,然后
設置減速速率是快速就可以達到吸附的效果
_collectionView.decelerationRate = UIScrollViewDecelerationRateFast;

下面貼出所有代碼

這里是.h

//
//  LBMiddleExpandLayout.h
//  LiuboMiddleExpandLayout
//
//  Created by liubo on 2023/7/8.
//#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN@interface LBMiddleExpandLayout : UICollectionViewFlowLayout@property (nonatomic, assign) BOOL scrollAnimation;/**<是否有分頁動畫*/
@property (nonatomic, assign) CGPoint lastOffset;/**<記錄上次滑動停止時contentOffset值*/- (instancetype)initWithSectionInset:(UIEdgeInsets)insetsandMiniLineSapce:(CGFloat)miniLineSpaceandMiniInterItemSpace:(CGFloat)miniInterItemSpaceandItemSize:(CGSize)itemSize;@endNS_ASSUME_NONNULL_END
//
//  LBMiddleExpandLayout.m
//  LiuboMiddleExpandLayout
//
//  Created by liubo on 2023/7/8.
//#import "LBMiddleExpandLayout.h"@interface LBMiddleExpandLayout ()@property (nonatomic, assign) UIEdgeInsets sectionInsets;
@property (nonatomic, assign) CGFloat miniLineSpace;
@property (nonatomic, assign) CGFloat miniInterItemSpace;
@property (nonatomic, assign) CGSize eachItemSize;@end@implementation LBMiddleExpandLayout/*初始化部分*/
- (instancetype)initWithSectionInset:(UIEdgeInsets)insetsandMiniLineSapce:(CGFloat)miniLineSpaceandMiniInterItemSpace:(CGFloat)miniInterItemSpaceandItemSize:(CGSize)itemSize
{self = [self init];if (self) {//基本尺寸/邊距設置self.sectionInsets = insets;self.miniLineSpace = miniLineSpace;self.miniInterItemSpace = miniInterItemSpace;self.eachItemSize = itemSize;}return self;
}- (instancetype)init
{self = [super init];if (self) {_lastOffset = CGPointZero;}return self;
}-(void)prepareLayout
{[super prepareLayout];self.scrollDirection = UICollectionViewScrollDirectionHorizontal;// 水平滾動/*設置內邊距*/self.sectionInset = _sectionInsets;self.minimumLineSpacing = _miniLineSpace;self.minimumInteritemSpacing = _miniInterItemSpace;self.itemSize = _eachItemSize;/*** decelerationRate系統給出了2個值:* 1. UIScrollViewDecelerationRateFast(速率快)* 2. UIScrollViewDecelerationRateNormal(速率慢)* 此處設置滾動加速度率為fast,這樣在移動cell后就會出現明顯的吸附效果*/self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;
}/*** 這個方法的返回值,就決定了collectionView停止滾動時的偏移量*/
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{CGFloat pageSpace = [self stepSpace];//計算分頁步距CGFloat offsetMax = self.collectionView.contentSize.width - (pageSpace + self.sectionInset.right + self.miniLineSpace);CGFloat offsetMin = 0;/*修改之前記錄的位置,如果小于最小contentsize或者大于最大contentsize則重置值*/if (_lastOffset.x<offsetMin){_lastOffset.x = offsetMin;}else if (_lastOffset.x>offsetMax){_lastOffset.x = offsetMax;}CGFloat offsetForCurrentPointX = ABS(proposedContentOffset.x - _lastOffset.x);//目標位移點距離當前點的距離絕對值CGFloat velocityX = velocity.x;BOOL direction = (proposedContentOffset.x - _lastOffset.x) > 0;//判斷當前滑動方向,手指向左滑動:YES;手指向右滑動:NOif (offsetForCurrentPointX > pageSpace/8. && _lastOffset.x>=offsetMin && _lastOffset.x<=offsetMax){NSInteger pageFactor = 0;//分頁因子,用于計算滑過的cell個數if (velocityX != 0){/*滑動*/pageFactor = ABS(velocityX);//速率越快,cell滑過數量越多}else{/*** 拖動* 沒有速率,則計算:位移差/默認步距=分頁因子*/pageFactor = ABS(offsetForCurrentPointX/pageSpace);}/*設置pageFactor上限為2, 防止滑動速率過大,導致翻頁過多*/pageFactor = pageFactor<1?1:(pageFactor<3?1:2);CGFloat pageOffsetX = pageSpace*pageFactor;proposedContentOffset = CGPointMake(_lastOffset.x + (direction?pageOffsetX:-pageOffsetX), proposedContentOffset.y);}else{/*滾動距離,小于翻頁步距一半,則不進行翻頁操作*/proposedContentOffset = CGPointMake(_lastOffset.x, _lastOffset.y);}//記錄當前最新位置_lastOffset.x = proposedContentOffset.x;return proposedContentOffset;
}/***計算每滑動一頁的距離:步距*/
-(CGFloat)stepSpace
{return self.eachItemSize.width + self.miniLineSpace;
}/*** 當collectionView的顯示范圍發生改變的時候,是否需要重新刷新布局* 一旦重新刷新布局,就會重新調用 layoutAttributesForElementsInRect:方法*/
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{return YES;
}/***防止報錯先復制attributes*/
- (NSArray *)getCopyOfAttributes:(NSArray *)attributes
{NSMutableArray *copyArr = [NSMutableArray new];for (UICollectionViewLayoutAttributes *attribute in attributes) {[copyArr addObject:[attribute copy]];}return copyArr;
}/***設置放大動畫*/
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{/*獲取rect范圍內的所有subview的UICollectionViewLayoutAttributes*/NSArray *arr = [self getCopyOfAttributes:[super layoutAttributesForElementsInRect:rect]];/*動畫計算*/if (self.scrollAnimation){/*計算屏幕中線*/CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.bounds.size.width/2.0f;/*刷新cell縮放*/for (UICollectionViewLayoutAttributes *attributes in arr) {CGFloat distance = fabs(attributes.center.x - centerX);/*移動的距離和屏幕寬度的的比例*/CGFloat apartScale = distance/self.collectionView.bounds.size.width;/*把卡片移動范圍固定到 -π/4到 +π/4這一個范圍內*/CGFloat scale = fabs(cos(apartScale * M_PI/4));/*設置cell的縮放按照余弦函數曲線越居中越趨近于1*/CATransform3D plane_3D = CATransform3DIdentity;plane_3D = CATransform3DScale(plane_3D, 1, scale, 1);attributes.transform3D = plane_3D;}}return arr;
}@end

使用的地方

//
//  LLLeftPointBannerController.m
//  LiuboMiddleExpandLayout_Example
//
//  Created by liubo on 2023/10/10.
//  Copyright ? 2023 liubo. All rights reserved.
//#import "LLLeftPointBannerController.h"
#import "LBMiddleExpandLayout.h"
#import "LBCollectionViewCell.h"@interface LLLeftPointBannerController () <UICollectionViewDataSource, UICollectionViewDelegate>@property (nonatomic, strong) UICollectionView *collectionView;@property (nonatomic, strong) NSMutableArray *signsArray;@end@implementation LLLeftPointBannerController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor whiteColor];[self.view addSubview:self.collectionView];for (int i = 0; i < 10; i ++) {[self.signsArray addObject:[NSString stringWithFormat:@"%d", i]];}[self.collectionView reloadData];// Do any additional setup after loading the view.
}#pragma mark - UICollectionViewDataSource, UICollectionViewDelegate- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {return 1;
}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {return self.signsArray.count;
}- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {//自定義item的UIEdgeInsetsreturn UIEdgeInsetsMake(0, 10 * PLUS_SCALE, 0, 0);
}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {LBCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([LBCollectionViewCell class]) forIndexPath:indexPath];NSString *titleString = self.signsArray[indexPath.item];cell.titleString = titleString;return cell;
}#pragma mark  - lazy load- (UICollectionView *)collectionView
{if (!_collectionView) {LBMiddleExpandLayout *layout = [[LBMiddleExpandLayout alloc] initWithSectionInset:UIEdgeInsetsZeroandMiniLineSapce:15 * PLUS_SCALEandMiniInterItemSpace:15 * PLUS_SCALEandItemSize:CGSizeMake(250 * PLUS_SCALE, 150)];layout.scrollAnimation = NO;_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];_collectionView.delegate = self;_collectionView.dataSource = self;_collectionView.pagingEnabled = NO;_collectionView.decelerationRate = UIScrollViewDecelerationRateFast;_collectionView.showsHorizontalScrollIndicator = NO;_collectionView.backgroundColor = [UIColor clearColor];[_collectionView registerClass:[LBCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([LBCollectionViewCell class])];[_collectionView setFrame:CGRectMake(0,  100, SCREEN_WIDTH,150)];}return _collectionView;
}- (NSMutableArray *)signsArray
{if (!_signsArray) {_signsArray = [NSMutableArray array];}return _signsArray;
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

本文demo鏈接: link

這里是之前寫的一個,使用自定義視圖實現的,沒有使用
UICollectionViewLayout 實現
鏈接: link

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21429.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21429.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21429.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

文章解讀與仿真程序復現思路——電力系統自動化EI\CSCD\北大核心《具有源荷不平衡特性的配電網智能軟開關和儲能聯合規劃》

本專欄欄目提供文章與程序復現思路&#xff0c;具體已有的論文與論文源程序可翻閱本博主免費的專欄欄目《論文與完整程序》 論文與完整源程序_電網論文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 電網論文源程序-CSDN博客電網論文源…

CTF_RE學習

學了一個 map&#xff08;&#xff09;函數的使用 import base64rawData "e3nifIH9b_CndH" target list(map(ord, rawData)) # map 函數將 rawData 中的每個字符傳遞給 ord 函數。ord 函數返回給定字符的 Unicode 碼點 print(target) # 打印 map 對象的內存地址&…

汽車線束搭鐵與接地

一、搭鐵與接地的概念 首先在這里解釋一下“搭鐵”與“接地”的概念&#xff0c;不要混為一團&#xff01; 先說接地&#xff0c;大地是可導電的&#xff0c;其電位通常取為零。電力系統和電氣裝置的中性點、電氣設備的外露導電部分及裝置外導電部分通過導體與大地相連&#xf…

MySQL數據庫的約束

MySQL對于數據庫存儲的數據, 做出一些限制性要求, 就叫做數據庫的"約束". 在每一列的 列名, 類型 后面加上"約束". 一. not null (非空) 指定某列不能存儲null值. 二. unique (唯一) 保證這一列的每行必須有唯一值. 我們可以看到, 給 table 的 sn 列插…

【微服務】docker部署redis,一主二從三哨兵,讀寫分離

配置redis讀寫分離 3臺虛擬機 創建目錄用于掛載 mkdir -p /root/redis/{conf,data,logs} #master配置文件 bind 0.0.0.0 //任何ip都能訪問 port 6379 //redis端口號 logfile "/data/redis.log" //日志文件存放位置&#xff0c;啟動redis之前設置為空&#xff…

prometheus docker部署

1.安裝Docker sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors":["https://hub-mirror.c.163.com"] } EOF export DOWNLOAD_URL"https://hub-mirror.163.com/docker-ce" curl -fsSL https://ge…

TypeScript 中的聲明合并

1. 聲明合并的概念 聲明合并是指當 TypeScript 遇到多個同名的聲明時&#xff0c;會將它們合并為一個單一的聲明。這使得開發者可以分散地定義同一個實體的不同部分&#xff0c;最終將它們合并為一個整體。在進行聲明合并時&#xff0c;TypeScript 會根據不同類型的聲明進行不…

【LIN】STM32新能源汽車LIN通信實現過程

【LIN】STM32新能源汽車LIN通信實現過程 文章目錄 前言一、軟件二、接線圖三、硬件原理圖四、上位機五、PICO示波器串行解碼1.軟件中的LIN波特率設置-192002.PIC設置3.PIC串行解碼 六.引用總結 前言 【電機控制】直流有刷電機、無刷電機匯總——持續更新 使用工具&#xff1a;…

godot.bk

1.搜索godot國內鏡像&#xff0c;直接安裝&#xff0c;mono是csharp版本 2.直接解壓&#xff0c;50m&#xff0c;無需安裝&#xff0c;直接運行 3.godot里分為場景&#xff0c;節點 主場景用control場景&#xff0c;下面掛textureact放背景圖片&#xff0c;右鍵實例化子場景把…

961題庫 北航計算機 計算機網絡 附答案 簡答題形式

有題目和答案&#xff0c;沒有解析&#xff0c;不懂的題問大模型即可&#xff0c;無償分享。 第1組 習題 某網絡拓撲如題下圖所示&#xff0c;其中 R 為路由器&#xff0c;主機 H1&#xff5e;H4 的 IP 地址配置以及 R 的各接口 IP 地址配置如圖中所示。現有若干以太網交換機…

Python高效遍歷文件和目錄的方法

在 Python 中&#xff0c;遍歷文件和目錄可以使用 os、pathlib 等模塊。以下是一些高效遍歷文件和目錄的方法&#xff1a; 使用 os.walk() os.walk() 是一個高效的遞歸遍歷指定目錄及其子目錄的方法&#xff0c;它返回一個生成器&#xff0c;生成一個三元組 (root, dirs, fil…

Instruction-Tuningpromote tuning原理,對比區別

Instruction-Tuning 原理 Instruction-Tuning&#xff08;指令調優&#xff09;是一種通過對模型提供明確指令或任務描述&#xff0c;從而提升其在特定任務上的表現的技術。這種方法通過預先定義好的任務說明&#xff08;instructions&#xff09;對模型進行微調&#xff0c;使…

鴻蒙應用開發之OpenGL應用和X組件9

接著下來,我們來分析函數CreateProgram的實現,它是實現著色器程序的編譯、加載和刪除資源。 GLuint EGLCore::CreateProgram(const char *vertexShader, const char *fragShader) { if ((nullptr == vertexShader) || (nullptr == fragShader)) { OH_LOG_Print(L…

MySQL—函數—函數小結

一、引言 前面博客我們已經學完了MySQL的函數&#xff0c;下面快速的對MySQL的函數做一個小結。 在講解了MySQL的函數的時候&#xff0c;主要有四個方面&#xff1a; 1、字符串函數 &#xff08;1&#xff09;CONCAT&#xff1a;字符串連接 &#xff08;2&#xff09;LOWER、…

Java 多線程創建:三種主要方法

多線程編程是Java中一個重要的技術點&#xff0c;它允許程序并行執行多個任務&#xff0c;從而提高程序的執行效率。本文將詳細介紹在Java中創建多線程的三種主要方法&#xff1a;繼承Thread類、實現Runnable接口以及使用Callable和Future接口。 1. 繼承 Thread 類 繼承Threa…

【前端每日基礎】day34——HTTP和HTTPS

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;和HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是互聯網通信協議&#xff0c;用于在Web瀏覽器和Web服務器之間傳輸數據。以下是對HTTP和HTTPS的詳細介紹&#xff1a; HTTP&#xff08;Hypertext…

Ubuntu server 24 (Linux) IPtables 雙網卡 共享上網NAT 安裝配置DHCP

一 開啟路由轉發功能 sudo vim /etc/sysctl.conf net.ipv4.ip_forward1 sudo sysctl -p 二 安裝DHCP #更新軟件包列表&#xff1a; sudo apt update #安裝DHCP服務器 sudo apt install isc-dhcp-server #修改監聽網卡,根據實際修改 sudo vi /etc/default/isc-dhcp-server …

配置 HTTP 代理 (HTTP proxy)

配置 HTTP 代理 [HTTP proxy] 1. Proxies2. curl2.1. Environment2.2. Proxy protocol prefixes 3. Use an HTTP proxy (使用 HTTP 代理)3.1. Using the examples (使用示例)3.1.1. Linux or macOS3.1.2. Windows Command Prompt 3.2. Authenticating to a proxy (向代理進行身…

Tailwindcss Layout布局相關樣式及實戰案例,5萬字長文,附完整源碼和效果截圖

aspect 相關樣式類 基礎樣式 ClassPropertiesaspect-autoaspect-ratio: auto;aspect-squareaspect-ratio: 1 / 1;aspect-videoaspect-ratio: 16 / 9; 案例&#xff1a;引入B站視頻 Use the aspect-* utilities to set the desired aspect ratio of an element. 使用’ asp…

兩款 IntelliJ IDEA 的 AI 編程插件

介紹兩款 IntelliJ IDEA 的 AI 編程插件&#xff1a;通義靈碼和 CodeGeeX。 通義靈碼 這是由阿里推出的一個基于通義大模型的 AI 編碼助手。 它提供了代碼智能生成、研發智能問答等功能。通義靈碼經過海量優秀開源代碼數據訓練&#xff0c;可以根據當前代碼文件及跨文件的上下…