iOS 吸顶效果

news2024/11/25 16:01:08

项目中,在列表向上滚动时,有时需要将某个控件置顶,这就是我们常见的吸顶效果。

1. UITableView 吸顶效果

UITableView是自带吸顶效果,我们把需要置顶的控件设置为SectionHeaderView,这样在滚动时,该控件会自动置顶。

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UKNestedTableView alloc] init];
        
        _tableView.bounces = NO;
        _tableView.showsVerticalScrollIndicator = NO;

        _tableView.delegate = self;
        _tableView.dataSource = self;
        
        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CellId"];
    }
    return _tableView;
}

#pragma mark - UITableViewDataSource -
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        return 1;
    }
    return 20;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        return 150;
    }
    return 60;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (section == 1) {
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 50)];
        headerView.backgroundColor = [UIColor blueColor];
        return headerView;
    }
    return nil;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    if (section == 1) {
        return 50;
    }
    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId" forIndexPath:indexPath];
    
    if (indexPath.section == 0) {
        cell.backgroundColor = [UIColor yellowColor];
        cell.textLabel.text = @"section 0";
    } else {
        if (indexPath.row % 2 == 0) {
            cell.backgroundColor = [UIColor grayColor];
        } else {
            cell.backgroundColor = [UIColor whiteColor];
        }
        cell.textLabel.text = [NSString stringWithFormat:@"item - %ld", indexPath.row];
    }
    
    return cell;
}

自定义UKNestedTableView

@implementation UKNestedTableView

- (instancetype)init {
    self = [super initWithFrame:CGRectZero style:UITableViewStylePlain];

    if (self) {
        self.backgroundColor = [UIColor whiteColor];
        self.separatorColor = [UIColor clearColor];
        
        self.separatorStyle = UITableViewCellSeparatorStyleNone;
                
        if (@available(iOS 11.0, *)) {
            self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }

        self.estimatedRowHeight = 0.000;
        self.estimatedSectionHeaderHeight = 0.000;
        self.estimatedSectionFooterHeight = 0.000;
        
        if (@available(iOS 13.0,*)) {
            self.automaticallyAdjustsScrollIndicatorInsets = NO;
        }

        if (@available(iOS 15.0,*)) { // 去除表格头留白
            self.sectionHeaderTopPadding = YES;
         }
    }
    return self;
}

@end

效果如下

在这里插入图片描述

2. 带TabView的吸顶效果

UITableView的吸顶效果能满足部分的要求,但在实际应用中,需要置顶的往往是一些标签页,对应的也是多个列表。

我们用UKTabView作为置顶的控件,并对应多个内容。

- (UKTabView *)tabView {
    if (!_tabView) {
        _tabView = [[UKTabView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 50)];
        [_tabView setIndicatorWidth:80 height:2 radius:1 color:[UIColor blueColor]];
        
        UKCustomTabItemView *tabItemView1 = [[UKCustomTabItemView alloc] init];
        [tabItemView1 setText:@"选项1"];
        [_tabView addItemView:tabItemView1];
        
        UKCustomTabItemView *tabItemView2 = [[UKCustomTabItemView alloc] init];
        [tabItemView2 setText:@"选项2"];
        [_tabView addItemView:tabItemView2];
        
        _tabView.delegate = self;
        
        [_tabView setSelection:0];
    }
    return _tabView;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (section == 1) {
        return self.tabView;
    }
    return nil;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId" forIndexPath:indexPath];
    if (indexPath.section == 0) {
        cell.backgroundColor = [UIColor yellowColor];
        cell.textLabel.text = @"section 0";
    } else {
        if (indexPath.row % 2 == 0) {
            if (self.selection == 0) {
                cell.backgroundColor = [UIColor grayColor];
            } else {
                cell.backgroundColor = [UIColor darkGrayColor];
            }
        } else {
            cell.backgroundColor = [UIColor whiteColor];
        }
        cell.textLabel.text = [NSString stringWithFormat:@"item %ld - %ld", self.selection, indexPath.row];
    }
    
    return cell;
}

#pragma mark - UKTabViewDelegate -
- (void)onTabViewSelected:(UKTabView *)tabView position:(NSInteger)position {
    self.selection = position;
    [self.tableView reloadData];
}

效果如下
在这里插入图片描述

上述的方法简单地实现了标签页置顶和选项卡切换功能,但由于我们只能共用一个列表,所以会发生两个标签页都滚动的现象。

为此,我们需要优化滚动的偏移,首先在滚动结束时记录偏移量,然后在切换标签页时设置原有的偏移量。

@property(nonatomic, assign) NSInteger selection;
@property(nonatomic, assign) CGFloat tab1Offset;
@property(nonatomic, assign) CGFloat tab2Offset;

// 拖动结束
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    NSLog(@"scrollViewDidEndDragging");

    [self recordOffset:scrollView];
}

// 滚动结束
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"scrollViewDidEndDecelerating");

    [self recordOffset:scrollView];
}

- (void)recordOffset:(UIScrollView *)scrollView {
    if (self.selection == 0) {
        self.tab1Offset = scrollView.contentOffset.y;
        NSLog(@"tab1Offset = %.2f", self.tab1Offset);
    } else if (self.selection == 1) {
        self.tab2Offset = scrollView.contentOffset.y;
        NSLog(@"tab2Offset = %.2f", self.tab2Offset);
    }
}

在切换标签页时,设置实际的偏移量

- (void)onTabViewSelected:(UKTabView *)tabView position:(NSInteger)position {
    self.selection = position;
    [self.tableView reloadData];

    // 有时设置tableView.contentOffset无效,需要提前刷新
    [self.tableView layoutIfNeeded];
    if (position == 0) {
        self.tableView.contentOffset = CGPointMake(0, self.tab1Offset);
    } else if (position == 1) {
        self.tableView.contentOffset = CGPointMake(0, self.tab2Offset);
    }
}

效果如下
在这里插入图片描述

虽然我们记录了原有的偏移量,但从实际的效果来看,切换时TabView会在同样的位置,闪烁比较严重。为此,我们需要尽量保持TabView的位置。

- (void)onTabViewSelected:(UKTabView *)tabView position:(NSInteger)position {
    self.selection = position;
    [self.tableView reloadData];

    [self.tableView layoutIfNeeded];
    if (position == 0) {
        self.tab1Offset = [self getDestOffset:self.tab1Offset originOffset:self.tab2Offset];
        self.tableView.contentOffset = CGPointMake(0, self.tab1Offset);
    } else if (position == 1) {
        self.tab2Offset = [self getDestOffset:self.tab2Offset originOffset:self.tab1Offset];
        self.tableView.contentOffset = CGPointMake(0, self.tab2Offset);
    }
}

// 如果TabView已经置顶,切换时保持置顶。
// 1、如果切换后的内容已经置顶,保持原有效果
// 2、如果切换后的内容没有置顶,修改切换后的内容为置顶
// 如果TabView没有制度,切换后保持一致
- (CGFloat)getDestOffset:(CGFloat)destOffset originOffset:(CGFloat)originOffset {
    if (originOffset >= 150) {
        if (destOffset >= 150) {
            return destOffset;
        } else {
            return 150;
        }
    } else {
        return originOffset;
    }
}

效果如下
在这里插入图片描述

虽然现在的方案已经解决了大部分的需求,但还是留下了一点瑕疵,

  1. 内容只能用UIScrollView显示
  2. 为了保持UKTableView保持位置不变,不能完全保证内容的偏移位置。
  3. 如果一个内容较短的情况下,依然会有偏移量的问题,虽然我们可以通过填充空白内容来改善这个问题,但又增加了很多工作量。
  4. 内容切换时没有平顺的效果。

3. UITableView+UICollectionView嵌套

为了尽可能的完善我们的吸顶效果,我们尝试用UITableView+UICollectionView的组合来实现吸顶和左右滑动二种效果。

我们自定义UKNestedScrollView

@interface UKNestedScrollView()

@property(nonatomic, strong) NSMutableArray <UITableView *> *contentViewArray;
@property(nonatomic, assign) BOOL dragging;

@end

@implementation UKNestedScrollView

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

// 设置表头
- (void)setHeaderView:(UIView *)headerView {
    self.tableView.tableHeaderView = headerView;
    self.headerHeight = headerView.frame.size.height;
}

// 添加标签页和内容
- (void)addTabView:(UKTabItemView *)itemView contentView:(UITableView *)contentView {
    [self.tabView addItemView:itemView];
    
    [self.contentViewArray addObject:contentView];
    
    [self.collectionView reloadData];
}


- (void)setupInitialUI {
    // UKNestedScrollView包含一个UITableView
    [self addSubview:self.tableView];
    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.bottom.equalTo(self);
    }];
}

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UKNestedTableView alloc] init];
        
        _tableView.bounces = NO;
        _tableView.showsVerticalScrollIndicator = NO;

        _tableView.delegate = self;
        _tableView.dataSource = self;
        
        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CellId"];
    }
    return _tableView;
}

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UKNestedTableView alloc] init];
        
        _tableView.bounces = NO;
        _tableView.showsVerticalScrollIndicator = NO;

        _tableView.delegate = self;
        _tableView.dataSource = self;
        
        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CellId"];
    }
    return _tableView;
}

// SectionHeaderView包含UKTabView和UICollectionView
- (UIView *)sectionHeaderView {
    if (!_sectionHeaderView) {
        _sectionHeaderView = [[UIView alloc] initWithFrame:self.frame];
        
        [_sectionHeaderView addSubview:self.tabView];
        
        [_sectionHeaderView addSubview:self.collectionView];
    }
    return _sectionHeaderView;
}

- (UKTabView *)tabView {
    if (!_tabView) {
        _tabView = [[UKTabView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 50)];
        [_tabView setIndicatorWidth:80 height:2 radius:1 color:[UIColor blueColor]];

        _tabView.delegate = self;
    }
    return _tabView;
}

- (UICollectionView *)collectionView {
    if (!_collectionView) {
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        layout.itemSize = CGSizeMake(self.frame.size.width, self.frame.size.height - 50);
        layout.minimumLineSpacing = CGFLOAT_MIN;
        layout.minimumInteritemSpacing = CGFLOAT_MIN;
        
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 50, self.frame.size.width, self.frame.size.height - 50) collectionViewLayout:layout];
        _collectionView.pagingEnabled = YES;
        _collectionView.bounces = NO;
        _collectionView.showsHorizontalScrollIndicator = NO;

        _collectionView.dataSource = self;
        _collectionView.delegate = self;
        
        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"CellId"];
    }
    return _collectionView;
}

#pragma mark - UITableViewDataSource -
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return self.frame.size.height;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    return self.sectionHeaderView;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [[UITableViewCell alloc] init];
}

#pragma mark - UICollectionViewDataSource -
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.contentViewArray.count;
}

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellId" forIndexPath:indexPath];
    
    UITableView *contentView = self.contentViewArray[indexPath.row];
    [contentView removeFromSuperview];
    
    [cell.contentView addSubview:contentView];
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.bottom.equalTo(cell.contentView);
    }];
    
    return cell;
}


#pragma mark - UIScrollViewDelegate -
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    if (scrollView == self.collectionView) {
        self.dragging = YES;
    }
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == self.collectionView) {
        if (self.dragging) {
            CGFloat width = scrollView.contentOffset.x;
            NSInteger page = width/self.frame.size.width + 0.5;
            
            [self.tabView setSelection:page offsetRatio:(width/self.frame.size.width - page)];
        }
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if (scrollView == self.collectionView) {
        CGFloat width = scrollView.contentOffset.x;
        NSInteger page = width/self.frame.size.width + 0.5;

        [self.tabView setSelection:page];
        self.dragging = NO;
    }
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (scrollView == self.collectionView && !decelerate) {
        CGFloat width = scrollView.contentOffset.x;
        NSInteger page = width/self.frame.size.width + 0.5;

        [self.tabView setSelection:page];
        self.dragging = NO;
    }
}
 
#pragma mark - UKTabViewDelegate -
- (void)onTabViewSelected:(UKTabView *)tabView position:(NSInteger)position {
    [self collectionViewScrollToPosition:position];
}

为了让UICollectionView内的手势能被UITableView接收,需要在UKNestedTableView里面加上

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

显示如下
在这里插入图片描述

我们可以看到当列表滑动时,两个列表都在滑动,而且里面的内容的滑动更快。这主要是因为例外两个列表都在滑动,所以里面的列表其实是两个滑动距离相加,所有我们需要在外面列表滑动时,禁止里面列表的滑动。

if (scrollView == self.tableView) {
    self.offset = self.tableView.contentOffset.y;
    // changed表示外面列表在滑动
    self.changed = YES;
} else {
    NSInteger position = 0;
    for (UIScrollView *contentView in self.contentViewArray) {
        if (contentView == scrollView) {
            // 如果外面列表滑动,禁止里面列表滑动事件
            if (self.changed) {
                scrollView.contentOffset = CGPointMake(0, [self.offsetArray[position] floatValue]);
                self.changed = NO;
            } else {
                // 记录当前页面偏移量,方便后面禁止事件
                self.offsetArray[position] = [NSNumber numberWithFloat:scrollView.contentOffset.y];
            }           
            break;
        }
        position++;
    }
}

效果如下
在这里插入图片描述

现在的效果已经基本满足了我们的需求,有吸顶效果、能左右滑动、能记录列表偏移量,内容滑动时也比较平顺了。

最后我们尝试了一下下拉时控制内容先下拉,也许后面有用

if (scrollView == self.tableView) {
    self.originOffset = self.offset;
    self.offset = self.tableView.contentOffset.y;
    self.changed = YES;
} else {
    NSInteger position = 0;
    for (UIScrollView *contentView in self.contentViewArray) {
        if (contentView == scrollView) {                
            CGFloat scrollViewOffset = scrollView.contentOffset.y - [self.offsetArray[position] floatValue];

            if (scrollViewOffset > 0) {
                if (self.changed) {
                    scrollView.contentOffset = CGPointMake(0, [self.offsetArray[position] floatValue]);
                    self.changed = NO;
                } else {
                    self.offsetArray[position] = [NSNumber numberWithFloat:scrollView.contentOffset.y];
                }
            } else if (scrollViewOffset < 0) {
                if (self.changed) {
                    self.offset = self.originOffset;

                    self.tableView.delegate = nil;
                    self.tableView.contentOffset = CGPointMake(0, self.offset);
                    self.tableView.delegate = self;

                    self.changed = NO;
                }
                self.offsetArray[position] = [NSNumber numberWithFloat:scrollView.contentOffset.y];
            }
            break;
        }
        position++;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424233.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

360城市全景,开启全新城市探索方式

引言 360城市全景技术的出现和发展&#xff0c;让我们的生活方式和观念发生了革命性的变化。在过去&#xff0c;我们只能通过实地旅行、图片和视频来了解不同城市的文化、建筑和风景。现在&#xff0c;通过360城市全景技术&#xff0c;我们可以像亲临现场一样&#xff0c;透过…

Vue实现自动化平台(四)--接口管理页面的实现

上一章&#xff1a; Vue实现自动化平台&#xff08;三&#xff09;_做测试的喵酱的博客-CSDN博客 github地址&#xff1a;https://github.com/18713341733/vuemiaotest 这个目前只是用来练手的&#xff0c;项目还没成型。等以后我写完了&#xff0c;再更新一下项目链接。 …

软件测试——概念篇

目录 一、软件的生命周期 二、瀑布模型&#xff08;Waterfall Model&#xff09; 优点&#xff1a; 缺点&#xff1a; 三、螺旋模型&#xff08;Spiral Model&#xff09; ​编辑优点&#xff1a; 缺点&#xff1a; 四、增量、迭代 区别&#xff1a; 五、敏捷 scrum…

windows下如何搭建属于自己的git服务器

前一阵子公司需要&#xff0c;领导让我给我们技术部搭建一个git服务器。以前看过教程&#xff0c;但自己没动手做过&#xff0c;开始按照网上的教程来&#xff0c;但搭建过程中发现还是不够详细&#xff0c;今天给大家一个比较详细的&#xff0c;希望对大家有帮助。 高能预警&…

DB2安装指导文档

操作系统windowsXP 版本&#xff1a;9.1.7 一&#xff1a;db2安装 用户为当前操作系统得用户 域为空 二&#xff1a;添加许可证&#xff0c;因为当前系统得试用期已到&#xff0c;所以必须输入有效的序列号&#xff0c;在安装数据库的过程中有时候也会莫名的死掉&#xff0c…

【LeetCode: 剑指 Offer II 099. 最小路径之和 | 暴力递归 | DFS =>记忆化搜索=>动态规划】

&#x1f34e;作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域新星创作者&#x1f3c6;&#xff0c;保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享&#x1f48e;&#x1f48e;&#x1f48e; &#x1f34e;座右…

4.java程序员必知必会类库之xml解析库

前言 百度百科解释 可扩展标记语言 (Extensible Markup Language, XML) &#xff0c;标准通用标记语言的子集&#xff0c;可以用来标记数据、定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。 XML是标准通用标记语言 可扩展性良好,内容与形式分离,遵…

(2023)基于多模态概率融合提示的少样本多模态情感分析

论文题目&#xff08;Title&#xff09;&#xff1a;Few-shot Multimodal Sentiment Analysis based on Multimodal Probabilistic Fusion Prompts 研究问题&#xff08;Question&#xff09;&#xff1a;用概率融合提示进行少样本的情感分析任务 研究动机&#xff08;Motiva…

IDEA插件-Lombok

在 Java 开发领域中&#xff0c;Lombok 插件已经成为一个非常流行的代码库。该插件让 Java 开发更加便捷、高效&#xff0c;因此提高了开发者的生产力。本文将对 Lombok 插件进行详细的介绍和分析。 1.Lombok是什么 Lombok 是一款 Java 开发工具&#xff0c;它可以通过注解来…

《离散数学导学》精炼——第8章(关系)

学无止境追求真&#xff0c;勤奋刻苦起点新。每日精进千里路&#xff0c;成功不是梦想闲。 文章目录引言正文第八章 关系定义定义域&#xff0c;值域关系的逆关系上的运算&#xff08;重点&#xff09;关系的合成同类关系和异类关系关系的性质&#xff08;重难点&#xff09;顺…

OpenAI-ChatGPT最新官方接口《嵌入向量式文本转换》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(五)(附源码)

Embeddings 嵌入向量式文本转换前言Overview 概述What are embeddings? 什么是嵌入&#xff1f;How to get embeddings 如何获取嵌入python代码示例cURL代码示例Embedding models 嵌入模型Second-generation models 第二代模型First-generation models (not recommended) 第一…

Kubernetes 多集群管理工具Rancher 使用介绍

目录 一、Rancher 简介 2.1 Run Kubernetes Everywhere 2.2 满足 IT 需求规范 2.3 赋能 DevOps 开发团队 2.4 Rancher API Server 的功能 2.4.1授权和角色权限控制 2.4.2使用 Kubernetes 的功能 2.4.3 配置云端基础信息 2.4.4 查看集群信息 2.5 编辑下游集群 二、Ra…

漏洞挖掘-漏洞扫描

一、工具 1.针对某种漏洞 &#xff08;1&#xff09;sqlmap python sqlmap.py -u "url" --dbs 枚举所有数据库 python sqlmap.py -u "url" --current -db 当前数据库 python sqlmap.py -u "url" -D db_name --tables …

如何做一个园区的导航地图?园区楼宇地图导航如何实现?

如何做一个园区的导航地图&#xff1f;电子地图已成为智慧园区应用的重要组成部分和刚需&#xff0c;基于地图一方面为来园区人员进行导引&#xff0c;同时为园区内部的可视化设备设施、停车引导、物联数据的展示、园区物业资产管理等提供高效的管理工具&#xff0c;融入电子地…

数据可视化有哪些方式?【图表类型大全】

我们通常所说的数据可视化是指狭义的数据可视化&#xff0c;即将数据以图表的方式进行呈现&#xff0c;常见于PPT、报表、新闻等场景。图表是数据可视化最基础的应用&#xff0c;它代表图形化的数据&#xff0c;通常以所用的图形符号命名&#xff0c;例如使用圆形符号的饼图、使…

让你的作品更出色——词云Word Cloud的制作方法(基于python,WordCloud,stylecloud)

让你的作品更出色—— 词云Word Cloud的制作方法&#xff08;基于python) 本文目录&#xff1a; 一、词云的简介 二、 实现原理和流程 1、制作词云流程图 2、词云实现原理 三、 实现词云的方式 1、安装词云相关模块库 2、WordCloud库 3、stylecloud库 四、总结 一、词…

Point-to Analysis指针分析(1)

Point-to Analysis指针分析&#xff08;1&#xff09;_音程的博客-CSDN博客 前言 指针分析是一个非常复杂的工作&#xff0c;这些工作很多方向&#xff0c;比如是否是上下文敏感分析或上下文不敏感分析&#xff0c;显然&#xff0c;这难易度是不一样地。比如下图。对于同一段…

SAP之Suse For SAP 12 sp5安装教程(超详细)

本文将详细介绍如何在VM环境下安装Suse For SAP 12 sp5。 关于VM创建Suse Linux虚拟机的教程参考另一个博客-SAP之VM创建SUSE虚拟机。本文建立在VM已经创建好了Suse虚拟机的前提下。 一、首先进入到安装界面&#xff0c;选择“Installation”&#xff0c;按“Enter” 二、勾选…

第七章 无线与移动网络

无线网络 无线网络基本结构 无线主机&#xff1b;运行端系统设备无线链路&#xff1b;通过无线通信链路连接到一个基站或者另一条无线主机基站&#xff1b;无线网络基础设施的一个关键部分&#xff0c;负责向与之关联的无线主机发送数据和接收主机发送的数据网络基础设施&…

ROS使用(9)tf2

许多tf2教程可用于C和Python。本教程经过了精简&#xff0c;以完成C或Python。如果你想同时学习C和Python&#xff0c;你应该分别学习一次C和一次Python的教程。 工作区设置 Introduction to tf2.tf2的 介绍 本教程将给予你一个很好的想法tf2可以为你做什么。 它在一个使用tur…