iOS自定义滚动条
- 引言
- 为什么要自定义ScrollIndictor
- 现有滚动条显示方案
- ( void) setAlpha:( CGFloat)alpha {
if ( self. superview. tag == noDisableVerticalScrollTag) {
if (alpha == 0 && self. autoresizingMask == UIViewAutoresizingFlexibleLeftMargin) {
if ( self. frame. size. width < 10 && self. frame. size. height > self. frame. size. width) {
UIScrollView *sc = ( UIScrollView*) self. superview;
if (sc. frame. size. height < sc. contentSize. height) {
return;
}
}
}
}
if ( self. superview. tag == noDisableHorizontalScrollTag) {
if (alpha == 0 && self. autoresizingMask == UIViewAutoresizingFlexibleTopMargin) {
if ( self. frame. size. height < 10 && self. frame. size. height < self. frame. size. width) {
UIScrollView *sc = ( UIScrollView*) self. superview;
if (sc. frame. size. width < sc. contentSize. width) {
return;
}
}
}
}
[ super setAlpha:alpha];
}
- 现有方案存在的问题
- 开始自定义之旅
#import "Constants.h"
@implementation BaseCollectionView{
UIView *scrollIndicatorView;
CGFloat contentSizeHeight;
}
- ( void)drawRect:( CGRect)rect {
[ self enableCustomVerticalScrollIndicatorWithColor:[ UIColor lightGrayColor]];
}
- ( void)reloadData{
[ super reloadData];
[ self setNeedsDisplay];
}
- ( UIView *)createIndicatorViewWithFrame:( CGRect) frame{
UIView *indicator = [[ UIView alloc] initWithFrame:frame];
indicator. layer. cornerRadius = ScrollIndicatorWidth/ 2.0f;
// viewScrollIndicator.alpha = 0.0f;
// viewScrollIndicator.layer.borderWidth = 1.0f;
// viewScrollIndicator.layer.borderColor = indicatorColor.CGColor;
[ self addSubview:indicator];
return indicator;
}
//Calculate the real height of scroll indictor accroding to the content size.
- ( CGFloat)getNormalScrollIndictorHeight{
CGFloat percent = self. frame. size. height / self. contentSize. height;
float normalHeight = MAX( 0.0f,(percent * self.frame.size.height));
return normalHeight;
}
- ( void)enableCustomVerticalScrollIndicatorWithColor:( UIColor *)indicatorColor
{
self. showsVerticalScrollIndicator = NO;
float height = [ self getNormalScrollIndictorHeight];
CGRect frame = CGRectMake( self. frame. size. width - ScrollIndicatorWidth - ScrollIndicatorRightSpace, 0.0f, ScrollIndicatorWidth, height);
if( scrollIndicatorView == nil){
scrollIndicatorView = [ self createIndicatorViewWithFrame:frame];
[ self addKVOObservers];
}
else{
scrollIndicatorView. frame = frame;
}
[ scrollIndicatorView setBackgroundColor:[indicatorColor colorWithAlphaComponent: 0.75]];
//If content size is larger than frame size, the indictor will be displayed.
if( self. frame. size. height >= self. contentSize. height){
scrollIndicatorView. alpha = 0;
}
else{
scrollIndicatorView. alpha = 1.0;
}
[ self refreshVerticalScrollIndicator];
}
- ( void)refreshVerticalScrollIndicator
{
if ( self. contentSize. height <= 0) {
return;
}
//Get the current frame of scroll indicator
CGRect rect = scrollIndicatorView. frame;
//Get the normal height of Indicator
float normalHeight = [ self getNormalScrollIndictorHeight];
//Calculate the real content offset ratio.
CGFloat maxConentOffset = self. contentSize. height - self. frame. size. height;
CGFloat offsetRatio = self. contentOffset. y / maxConentOffset;
//Calculate the indictor offset
CGFloat maxIndicatorOffset = ( self. frame. size. height - normalHeight);
CGFloat indicatorOffset = offsetRatio * maxIndicatorOffset;
//if scrolling out of top limitation, the scroll indictor will be compressed.
if (indicatorOffset < 0) {
rect. size. height = normalHeight + indicatorOffset;
}
//if scrolling out of bottom limitation, the scroll indictor will be compressed again.
else if(indicatorOffset > self. frame. size. height - normalHeight){
rect. size. height = normalHeight- (indicatorOffset - maxIndicatorOffset);
// indicatorOffset = self.frame.size.height - normalHeight;
}
else{
rect. size. height = normalHeight;
}
rect. origin. y = self. contentOffset. y + MAX( 0.0f,indicatorOffset);
if (rect. size. height < ScrollIndicatorMinHeight) {
rect. size. height = ScrollIndicatorMinHeight;
}
scrollIndicatorView. frame = rect;
}
- ( void)dealloc
{
[ self removeKVOObservers];
}
#pragma mark - KVO
- ( void)addKVOObservers
{
[ self addObserver: self forKeyPath: @"contentSize" options:( NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context: NULL];
[ self addObserver: self forKeyPath: @"contentOffset" options:( NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context: NULL];
}
- ( void)removeKVOObservers
{
[ self removeObserver: self forKeyPath: @"contentSize"];
[ self removeObserver: self forKeyPath: @"contentOffset"];
}
- ( void) observeValueForKeyPath: ( NSString *) keyPath ofObject: ( id) object change: ( NSDictionary *) change context: ( void *) context
{
if ( self. contentSize. width > 0.0f) {
[ self refreshVerticalScrollIndicator];
/*
UIView *viewScrollIndicator = [self getViewForHorizontalScrollIndicator];
CGRect rect = self.frame;
CGFloat pourcent = self.contentOffset.x / self.contentSize.width;
viewScrollIndicator.hidden = self.contentSize.width < self.frame.size.width;
rect.size.width = self.frame.size.width * (self.frame.size.width / self.contentSize.width);
rect.origin.x = pourcent * self.frame.size.width;
viewScrollIndicator.frame = rect;
*/
}
}
- 有待完善和改进的地方
相关文章:
iOS自定义滚动条
引言 最近一直在做数据通信相关的工作,导致了UI上的一些bug一直没有解决。这两天终于能腾出点时间大概看了一下Redmine上的bug,发现有很多bug都是与系统滚动条有关系的。所以索性就关注一下这个小小的滚动条。 为什么要自定义ScrollIndictor 原有的Scrol…...
C++知识点2:把数据写进switch case结构,和写进json结构,在使用上有什么区别
将数据存储在Switch Case结构和JSON结构中有明显的区别,它们用于不同的目的和方式。以下是它们之间的主要区别: 1、用途和结构: Switch Case结构:Switch Case是一种条件语句,通常用于根据条件执行不同的代码块。它通常…...
肖sir__linux详解__003(vim命令)
linux 文本编辑命令 作用:用于编辑一个文件 用法:vim 文件名称 或者vi (1)编辑一个存在的文档 例子:编辑一个file1文件 vim aa (2)编辑一个文件不存在,会先创建文件,再…...
瑞芯微RK3588开发板:虚拟机yolov5模型转化、开发板上python脚本调用npu并部署 全流程
目录 0. 背景1. 模型转化1.1 基础环境1.2 创建python环境1.3 将yolov5s.pt转为yolov5s.onnx1.4 将yolov5s.onnx转为yolov5s.rknn 2. 开发板部署2.1. c版本2.1. python版本(必须是python 3.9) 3. 性能测试 0. 背景 全面国产化,用瑞芯微rk3588…...
【Redis专题】RedisCluster集群运维与核心原理剖析
目录 课程内容一、Redis集群架构模型二、Redis集群架构搭建(单机搭建)2.1 在服务器下新建各个节点的配置存放目录2.2 修改配置(以redis-8001.conf为例) 三、Java代码实战四、Redis集群原理分析4.1 槽位定位算法4.2 跳转重定位4.3 …...
我眼中的《视觉测量技术基础》
为什么会写这篇博客: 首先给大家说几点:看我的自我介绍对于学习这本书没有任何帮助,如果你是为了急切的想找一个视觉测量的解决方案那可以跳过自我介绍往下看或者换一篇博客看看,如果你是刚入门想学习计算机视觉的同学࿰…...
【Cisco Packet Tracer】管理方式,命令,接口trunk,VLAN
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
深入协议栈了解TCP的三次握手、四次挥手、CLOSE-WAIT、TIME-WAIT。
TCP网络编程的代码网上很多,这里就不再赘述,简单用一个图展示一下tcp网络编程的流程: 1、深入connect、listen、accept系统调用,进一步理解TCP的三次握手 这三个函数都是系统调用,我们可以分为请求连接方和被…...
接口自动化测试系列-yml管理测试用例
项目源码 目录结构及项目介绍 整体目录结构,目录说明参考 测试用例结构类似httprunner写法,可参考demo 主要核心函数 用例读取转换json import yaml import main import os def yaml_r():curpath f{main.BASE_DIR}/quality_management_logic/ops_ne…...
开源对象存储系统minio部署配置与SpringBoot客户端整合访问
文章目录 1、MinIO安装部署1.1 下载 2、管理工具2.1、图形管理工具2.2、命令管理工具2.3、Java SDK管理工具 3、MinIO Server配置参数3.1、启动参数:3.2、环境变量3.3、Root验证参数 4、MinIO Client可用命令 官方介绍: MinIO 提供高性能、与S3 兼容的对…...
Matlab之数组字符串函数汇总
一、前言 在MATLAB中,数组字符串是指由字符组成的一维数组。字符串可以包含字母、数字、标点符号和空格等字符。MATLAB提供了一些函数和操作符来创建、访问和操作字符串数组。 二、字符串数组具体怎么使用? 1、使用单引号或双引号括起来的字符序列 例…...
基于深度学习网络的火灾检测算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ................................................................................ load F…...
【Linux】高级IO和多路转接 | select/poll/epoll
多路转接和高级IO 咳咳,写的时候出了点问题,标点符号全乱了(批量替换了几次),干脆就把全文的逗号和句号都改成英文的了(不然代码块里面的代码都是中文标点就跑不动了) 1.高级IO 1.1 五种IO模型…...
el-select 支持多选 搜索远程数据 组件抽取
el-select 支持多选 搜索远程数据 组件抽取 使用方式 import selectView from ./components/selectView<el-form><el-form-item label"选择器"><selectView v-model"selValue" change"handleChange"></el-form-item> …...
el-table纵向垂直表头
参考:https://www.jianshu.com/p/1f38eaffd070 <el-tablestyle"width: 100%":data"getValues":show-header"false"border:cell-style"cellStyle" ><el-table-columnv-for"(item, index) in getHeaders"…...
Pinyin4j介绍和简单使用
前言 Pinyin4j是一个Java库,用于将汉字转换为拼音。它是由中国清华大学的Tsinghua University和中国科学院计算技术研究所的研究人员开发的。Pinyin4j可以用于Java应用程序中,以便在需要时将汉字转换为拼音。例如,它可以用于中文输入法、文本…...
【数据结构】查找
【数据结构】查找 数据结构中,有顺序查找、二分查找、散列查找、插值查找、斐波那契额查找 1.顺序查找 条件:待查找的元素与数组中的元素按顺序排列。算法:从数组的第一个元素开始,逐个比较,直到找到目标元素或遍历完…...
第一次面试
1.多态的原理 2.编译原理 3.HTTPS的加密原理 4.说一说C11新特性 5.平时用过哪些STL容器 6.STL的比较器 原来就是自定义工具类hhhhhh 7.函数指针用过吗 8.I/O多路复用 9.Redis 问的基本都背过,但是一紧张啥都忘了hhhhhhhhh...
Nacos配置文件更新+热更新+多环境配置共享+集群搭建
对服务配置文件 场景: 如果多个服务对应的配置文件都需要更改时,可以利用配置管理,方便对配置文件进行更新,而且是在本地配置前先读取nacos的配置文件,优先级大于本地配置文件 配置步骤 1.首先在Nacos中的配置列表中增…...
李宏毅-机器学习hw4-self-attention结构-辨别600个speaker的身份
一、慢慢分析学习pytorch中的各个模块的参数含义、使用方法、功能: 1.encoder编码器中的nhead参数: self.encoder_layer nn.TransformerEncoderLayer( d_modeld_model, dim_feedforward256, nhead2) 所以说,这个nhead的意思,就…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
