UI - 关于自动调整内边距问题的细节

本文探讨了iOS中控制器`automaticallyAdjustsScrollViewInsets`属性对tableView、collectionView等scrollView子控件的影响。内容包括自动调整内边距的场景,例如导航栏遮盖问题,多个scrollView的处理,以及不同控制器组合时的内边距调整行为。建议在存在多个scrollView时关闭自动调整以避免计算困扰。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iOS 7 以后 , 苹果推出了 控制器 automaticallyAdjustsScrollViewInsets 属性 , 目的在于自动帮我们调整所有继承于 scrollView控件的内边距 ,比如tableView , collectionView . automaticallyAdjustsScrollViewInsets 默认开启 .


具体例子1 :
默认情况下 automaticallyAdjustsScrollViewInsets = YES ,苹果为了使得在scrollView上的子控件能够比较美观的布局 , 而不出现一开始展示就出现了导航栏遮盖控件的现象 , 比如你在scrollView上添加了控件 , Y值小于64 , 那么就会被遮挡 . 所以在有导航栏情况下 , 苹果直接帮我们加了64的内边距 , 咱们写的时候从视觉上看就是导航栏底部是 Y = 0

下述tableView的cell本应从顶部开始布局 , 然后由于自动调整了内边距 ,导致位置下移 . 而滑动时出现穿透效果 , 说明导航栏下面部分也是属于tableView的 , 而并不是将tableView整体下移了64

    UITableView *tableView = [[UITableView alloc]initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
    tableView.delegate = self;
    tableView.dataSource = self;
    [self.view addSubview:tableView];

这里写图片描述


打印结果如下: 顶部内边距为自动调整 64
这里写图片描述

具体例子2: collectionView也是如此 , item本应在顶部 , 由于自动调整了内边距 , 而整体下移

    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
    flowLayout.minimumLineSpacing = 10.0;
    flowLayout.minimumInteritemSpacing = 10.0;
    flowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 20, 20);
    flowLayout.itemSize = CGSizeMake(100, 100);

    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];
    collectionView.delegate = self;
    collectionView.dataSource = self;
    collectionView.backgroundColor = [UIColor whiteColor];
    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    [self.view addSubview:collectionView];

这里写图片描述

具体例子3: scrollView

    UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    scrollView.contentSize = CGSizeMake(375, 2000);
    scrollView.backgroundColor = [UIColor yellowColor];

    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, 0, 200, 50)];
    label.backgroundColor = [UIColor redColor];
    [scrollView addSubview:label];

    [self.view addSubview:scrollView];

这里写图片描述

例子4:同时添加多个scrollView , 观察scrollView子控件自动调整状况

    UIScrollView *scrollView1 = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 100, 100, 100)];
    scrollView1.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1.0];
    [self.view addSubview:scrollView1];


    UIScrollView *scrollView2 = [[UIScrollView alloc]initWithFrame:CGRectMake(120, 100, 100, 100)];
    scrollView2.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1.0];
    [self.view addSubview:scrollView2];


    UIScrollView *scrollView3 = [[UIScrollView alloc]initWithFrame:CGRectMake(240,100, 100, 100)];
    scrollView3.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1.0];
    [self.view addSubview:scrollView3];

    UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(0,0, 50, 50)];
    view1.backgroundColor = [UIColor redColor];
    [scrollView1 addSubview:view1];

    UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(0,0, 50, 50)];
    view2.backgroundColor = [UIColor redColor];
    [scrollView2 addSubview:view2];

    UIView *view3 = [[UIView alloc]initWithFrame:CGRectMake(0,0, 50, 50)];
    view3.backgroundColor = [UIColor redColor];
    [scrollView3 addSubview:view3];


    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 250, [UIScreen mainScreen].bounds.size.width, 50)];
    label.text = @"这是一个添加到view上的测试label";
    label.textColor = [UIColor blackColor];
    label.backgroundColor = [UIColor grayColor];
    [self.view addSubview:label];

结果如下:
这里写图片描述


只有第一个添加上去的scrollView上的子控件 , 进行了自动调整 , 而其他的scrollView上的子控件并未进行自动调整 .
所以 , 如果当搭建一个界面 , 如果出现多个scrollView时 , 尽量把 automaticallyAdjustsScrollViewInsets = NO .方便计算


例子5:
当同时拥有导航控制器和tabbar标签栏控制器时 , 苹果会自动将上下的内间距分别调整 64 , 49 .

这里写图片描述

此时 , tableView上的所有控件也不会被底部的tabbar所遮挡 .


例子6:

当只拥有tabbar标签栏控制器时 , 不会自动调整内间距

这里写图片描述


例子7:

当设置了导航栏不透明时 , self.view上的所有控件 , 均从导航栏下为 0 点开始计算 , 且不再自动调整内边距 ~!!!

    self.view.backgroundColor = [UIColor whiteColor];

    //设置不透明
    self.navigationController.navigationBar.translucent = NO;

    self.tableView = [[UITableView alloc]initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view addSubview:self.tableView];

    UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(0,0, 50, 50)];
    view2.backgroundColor = [UIColor redColor];
    [self.view addSubview:view2];

这里写图片描述


3D图层如下:

这里写图片描述

细节问题 , 仅为了以后不再纠结 , 记不住也能写项目.

#include "mainwindow.h" #include "ui_Mainwindow.h" #include "qcustomplot.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // // 创建主工具栏 mainToolBar = new QToolBar("主工具栏", this); mainToolBar->setMovable(false); // 禁止工具栏移动 addToolBar(Qt::TopToolBarArea, mainToolBar); ui->customPlot->addGraph(); ui->customPlot->graph(0)->setPen(QPen(Qt::blue)); // 线条颜色为蓝色 // 生成一些数据点 QVector<double> x(251), y0(251); for (int i=0; i<251; ++i) { x[i] = i; y0[i] = qExp(-i/150.0)*qCos(i/10.0); // 指数衰减的余弦函数 } // 配置右轴和上轴显示刻度但不显示标签 ui->customPlot->xAxis2->setVisible(true); ui->customPlot->xAxis2->setTickLabels(false); ui->customPlot->yAxis2->setVisible(true); ui->customPlot->yAxis2->setTickLabels(false); // 使左轴和下轴的范围变化同步到右轴和上轴 connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange))); connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange))); // 将数据点传递给图形 ui->customPlot->graph(0)->setData(x, y0); // 自动调整坐标轴范围以适应图形 ui->customPlot->graph(0)->rescaleAxes(); // 允许用户通过鼠标拖动坐标轴范围、使用鼠标滚轮缩放以及通过点击选择图形 ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); // 计算图表中心位置 double xCenter = (ui->customPlot->xAxis->range().lower + ui->customPlot->xAxis->range().upper) / 2; double yCenter = (ui->customPlot->yAxis->range().lower + ui->customPlot->yAxis->range().upper) / 2; // 初始化垂直光标1 verticalLine1 = new QCPItemStraightLine(ui->customPlot); verticalLine1->setPen(QPen(Qt::red, 1, Qt::SolidLine)); verticalLine1->point1->setCoords(0, ui->customPlot->yAxis->range().lower); verticalLine1->point2->setCoords(0, ui->customPlot->yAxis->range().upper); verticalLine1->setVisible(false); // 初始化垂直光标1的标签 verticalLabel1 = new QCPItemText(ui->customPlot); verticalLabel1->setLayer("overlay"); // 确保标签显示在最上层 verticalLabel1->setClipToAxisRect(false); verticalLabel1->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); verticalLabel1->position->setType(QCPItemPosition::ptAxisRectRatio); verticalLabel1->position->setCoords(0, 0); // 初始位置 verticalLabel1->setText("Time: 0"); verticalLabel1->setFont(QFont(font().family(), 9)); verticalLabel1->setPen(QPen(Qt::red)); verticalLabel1->setBrush(QBrush(Qt::white)); verticalLabel1->setVisible(false); // 初始化垂直光标2 verticalLine2 = new QCPItemStraightLine(ui->customPlot); verticalLine2->setPen(QPen(Qt::green, 1, Qt::SolidLine)); // verticalLine2->point1->setCoords(0, ui->customPlot->yAxis->range().lower); // verticalLine2->point2->setCoords(0, ui->customPlot->yAxis->range().upper); verticalLine2->point1->setCoords(xCenter + 10, ui->customPlot->yAxis->range().lower); verticalLine2->point2->setCoords(xCenter + 10, ui->customPlot->yAxis->range().upper); verticalLine2->setVisible(false); // 初始化垂直光标2的标签 verticalLabel2 = new QCPItemText(ui->customPlot); verticalLabel2->setLayer("overlay"); // 确保标签显示在最上层 verticalLabel2->setClipToAxisRect(false); verticalLabel2->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); verticalLabel2->position->setType(QCPItemPosition::ptAxisRectRatio); verticalLabel2->position->setCoords(0, 0); // 初始位置 verticalLabel2->setText("Time: 0"); verticalLabel2->setFont(QFont(font().family(), 9)); verticalLabel2->setPen(QPen(Qt::red)); verticalLabel2->setBrush(QBrush(Qt::white)); verticalLabel2->setVisible(false); // 初始化水平光标1 horizontalLine1 = new QCPItemStraightLine(ui->customPlot); horizontalLine1->setPen(QPen(Qt::magenta, 1, Qt::SolidLine)); horizontalLine1->point1->setCoords(ui->customPlot->xAxis->range().lower, 0); horizontalLine1->point2->setCoords(ui->customPlot->xAxis->range().upper, 0); horizontalLine1->setVisible(false); // 初始化水平光标1的标签 horizontalLabel1 = new QCPItemText(ui->customPlot); horizontalLabel1->setLayer("overlay"); horizontalLabel1->setClipToAxisRect(false); horizontalLabel1->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter); horizontalLabel1->position->setType(QCPItemPosition::ptAxisRectRatio); horizontalLabel1->position->setCoords(0, 0); // 初始位置 horizontalLabel1->setText("Voltage: 0"); horizontalLabel1->setFont(QFont(font().family(), 9)); horizontalLabel1->setPen(QPen(Qt::red)); horizontalLabel1->setBrush(QBrush(Qt::white)); horizontalLabel1->setVisible(false); // 初始化水平光标2 horizontalLine2 = new QCPItemStraightLine(ui->customPlot); horizontalLine2->setPen(QPen(Qt::yellow, 1, Qt::SolidLine)); // horizontalLine2->point1->setCoords(ui->customPlot->xAxis->range().lower, 0); // horizontalLine2->point2->setCoords(ui->customPlot->xAxis->range().upper, 0); horizontalLine2->point1->setCoords(ui->customPlot->xAxis->range().lower, yCenter + 0.2); horizontalLine2->point2->setCoords(ui->customPlot->xAxis->range().upper, yCenter + 0.2); horizontalLine2->setVisible(false); // 初始化水平光标2的标签 horizontalLabel2 = new QCPItemText(ui->customPlot); horizontalLabel2->setLayer("overlay"); // 确保标签显示在最上层 horizontalLabel2->setClipToAxisRect(false); horizontalLabel2->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter); horizontalLabel2->position->setType(QCPItemPosition::ptAxisRectRatio); horizontalLabel2->position->setCoords(0, 0); // 初始位置 horizontalLabel2->setText("Voltage: 0"); horizontalLabel2->setFont(QFont(font().family(), 9)); horizontalLabel2->setPen(QPen(Qt::red)); horizontalLabel2->setBrush(QBrush(Qt::white)); horizontalLabel2->setVisible(false); // 初始化差值标签 diffLabel = new QCPItemText(ui->customPlot); diffLabel->setLayer("overlay"); diffLabel->setClipToAxisRect(false); diffLabel->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter); diffLabel->position->setType(QCPItemPosition::ptAxisRectRatio); diffLabel->position->setCoords(0.5, 0.05); // 顶部中间 diffLabel->setText("ΔT: 0.0, ΔV: 0.0"); diffLabel->setFont(QFont(font().family(), 10)); diffLabel->setVisible(false); cursorModeAction = new QAction("Cursor Mode", this); cursorModeAction->setIcon(QIcon(":/images/line_icon/rewind-button.png")); cursorModeAction->setCheckable(true); mainToolBar->addAction(cursorModeAction); connect(cursorModeAction, &QAction::triggered, this, &MainWindow::onCursorModeToggled); // 连接鼠标移动事件到 mouseMoveEvent 槽函数 connect(ui->customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoveEvent(QMouseEvent*))); connect(ui->customPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePressEvent(QMouseEvent*))); connect(ui->customPlot, SIGNAL(mouseRelease(QMouseEvent*)), this, SLOT(mouseReleaseEvent(QMouseEvent*))); } MainWindow::~MainWindow() { delete ui; } void MainWindow::onCursorModeToggled(bool checked) { cursorEditMode = checked; if (cursorEditMode) { // 进入光标模式,禁用缩放和拖动 ui->customPlot->setInteractions(QCP::iSelectPlottables); ui->statusbar->showMessage("光标编辑模式已开启 - 左键添加/移动垂直光标,右键添加/移动水平光标"); } else { // 退出光标模式,恢复缩放和拖动 ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); ui->statusbar->showMessage("光标编辑模式已关闭"); // 隐藏所有光标和标签 verticalLine1->setVisible(false); verticalLine1->setVisible(false); horizontalLine1->setVisible(false); verticalLabel1->setVisible(false); horizontalLabel1->setVisible(false); verticalLine2->setVisible(false); horizontalLine2->setVisible(false); verticalLabel2->setVisible(false); horizontalLabel2->setVisible(false); diffLabel->setVisible(false); verticalLine1Created = false; horizontalLine1Created = false; verticalLine2Created = false; horizontalLine2Created = false; } ui->customPlot->replot(); } void MainWindow::mousePressEvent(QMouseEvent *event) { if (cursorEditMode) { double x = ui->customPlot->xAxis->pixelToCoord(event->x()); double y = ui->customPlot->yAxis->pixelToCoord(event->y()); // 重置拖动状态 isVerticalDragging1 = false; isHorizontalDragging1 = false; isVerticalDragging2 = false; isHorizontalDragging2 = false; // 左键:垂直光标(时间光标) if (event->button() == Qt::LeftButton) { // 如果第一个垂直光标未创建,则创建 if (!verticalLine1Created) { setupVerticalCursor(verticalLine1, verticalLabel1, x); verticalLine1Created = true; isVerticalDragging1 = true; } // 如果第一个已创建但第二个未创建,则创建第二个 else if (!verticalLine2Created) { setupVerticalCursor(verticalLine2, verticalLabel2, x); verticalLine2Created = true; isVerticalDragging2 = true; } // 如果两个都已创建,则判断点击的是哪个(靠近哪个就拖动哪个) else { // 移动最近的光标 double dist1 = qAbs(x - verticalLine1->point1->coords().x()); double dist2 = qAbs(x - verticalLine2->point1->coords().x()); if (dist1 < dist2) { isVerticalDragging1 = true; } else { isVerticalDragging2 = true; } } } // 右键:水平光标(电压光标) else if (event->button() == Qt::RightButton) { // 类似垂直光标的处理 if (!horizontalLine1Created) { setupHorizontalCursor(horizontalLine1, horizontalLabel1, y); horizontalLine1Created = true; isHorizontalDragging1 = true; } else if (!horizontalLine2Created) { setupHorizontalCursor(horizontalLine2, horizontalLabel2, y); horizontalLine2Created = true; isHorizontalDragging2 = true; } else { double dist1 = qAbs(y - horizontalLine1->point1->coords().y()); double dist2 = qAbs(y - horizontalLine2->point1->coords().y()); if (dist1 < dist2) { isHorizontalDragging1 = true; } else { isHorizontalDragging2 = true; } } } ui->customPlot->replot(); // 确保每次点击后立即重绘 } QMainWindow::mousePressEvent(event); } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if (cursorEditMode) { double x = ui->customPlot->xAxis->pixelToCoord(event->x()); double y = ui->customPlot->yAxis->pixelToCoord(event->y()); // 更新垂直光标位置 if (isVerticalDragging1) { moveVerticalCursor(verticalLine1, verticalLabel1, x); } if (isVerticalDragging2) { moveVerticalCursor(verticalLine2, verticalLabel2, x); } // 更新水平光标位置 if (isHorizontalDragging1) { moveHorizontalCursor(horizontalLine1, horizontalLabel1, y); } if (isHorizontalDragging2) { moveHorizontalCursor(horizontalLine2, horizontalLabel2, y); } // 更新差值 updateCursorDiffs(); ui->customPlot->replot(); } QMainWindow::mouseMoveEvent(event); } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { // 释放拖动状态 isVerticalDragging1 = false; isVerticalDragging2 = false; isHorizontalDragging1 = false; isHorizontalDragging2 = false; QMainWindow::mouseReleaseEvent(event); } void MainWindow::setupVerticalCursor(QCPItemStraightLine *line, QCPItemText *label, double x) { line->point1->setCoords(x, ui->customPlot->yAxis->range().lower); line->point2->setCoords(x, ui->customPlot->yAxis->range().upper); line->setVisible(true); label->setVisible(true); updateVerticalCursorLabel(label, x); // 更新标签位置和文本 } void MainWindow::moveVerticalCursor(QCPItemStraightLine *line, QCPItemText *label, double x) { line->point1->setCoords(x, ui->customPlot->yAxis->range().lower); line->point2->setCoords(x, ui->customPlot->yAxis->range().upper); updateVerticalCursorLabel(label, x); } void MainWindow::updateVerticalCursorLabel(QCPItemText *label, double x) { // 标签位置:在光标顶部,X轴位置为光标位置(转换为坐标轴比例),Y轴位置为1(底部) label->position->setCoords( (x - ui->customPlot->xAxis->range().lower) / ui->customPlot->xAxis->range().size(), 1.0); label->setText(QString("Time: %1").arg(x, 0, 'f', 2)); } void MainWindow::setupHorizontalCursor(QCPItemStraightLine *line, QCPItemText *label, double y) { // line->point1->setCoords(y, ui->customPlot->yAxis->range().lower);x // line->point2->setCoords(y, ui->customPlot->yAxis->range().upper); line->point1->setCoords(ui->customPlot->xAxis->range().lower,y); line->point2->setCoords(ui->customPlot->xAxis->range().upper,y); line->setVisible(true); label->setVisible(true); updateHorizontalCursorLabel(label, y); // 确保调用正确的更新标签函数 } void MainWindow::moveHorizontalCursor(QCPItemStraightLine *line, QCPItemText *label, double y) { // line->point1->setCoords(y, ui->customPlot->yAxis->range().lower); // line->point2->setCoords(y, ui->customPlot->yAxis->range().upper); line->point1->setCoords(ui->customPlot->xAxis->range().lower,y); line->point2->setCoords(ui->customPlot->xAxis->range().upper,y); updateHorizontalCursorLabel(label, y); // 确保调用正确的更新标签函数 } void MainWindow::updateHorizontalCursorLabel(QCPItemText *label, double y) { // 标签位置:在光标左侧,X轴位置为0(左侧),Y轴位置为光标位置(转换为坐标轴比例) // label->position->setCoords( // (y - ui->customPlot->xAxis->range().lower) / ui->customPlot->xAxis->range().size(), // 1.0); label->position->setCoords(0.0, (y - ui->customPlot->yAxis->range().lower) / ui->customPlot->yAxis->range().size()); label->setText(QString("Voltage: %1").arg(y, 0, 'f', 2)); } void MainWindow::updateCursorDiffs() { double timeDiff = 0.0; double voltageDiff = 0.0; // 计算时间差(两个垂直光标) if (verticalLine1Created && verticalLine2Created) { double t1 = verticalLine1->point1->coords().x(); double t2 = verticalLine2->point1->coords().x(); timeDiff = qAbs(t2 - t1); } // 计算电压差(两个水平光标) if (horizontalLine1Created && horizontalLine2Created) { double v1 = horizontalLine1->point1->coords().y(); double v2 = horizontalLine2->point1->coords().y(); voltageDiff = qAbs(v2 - v1); } // 更新差值标签 diffLabel->setText(QString("ΔT: %1, ΔV: %2").arg(timeDiff, 0, 'f', 3).arg(voltageDiff, 0, 'f', 3)); diffLabel->setVisible(verticalLine1Created && verticalLine2Created && horizontalLine1Created && horizontalLine2Created); } 上述程序,点击右键添加水平光标,只能添加第2条水平光标,而且右键移动第2条水平光标,该光标的标签与光标相差1个单位,上述问题怎么解决
最新发布
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值