iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图

2023-05-16

话不多说,先来看看效果:

1.饼图(扇形图)

2.柱状图

3.折线图

样子粗糙,见笑了。

现在来看看实现过程

一、饼图(扇形图)

1.实现思路

实现思路其实很简单,首先算传入数据数组的数据总和,然后根据每个数据占比来乘以2π,得到每个数据的弧度,然后在循环中利用UIBezierPath的addArcWithCenter: radius: startAngle: endAngle: clockwise:方法设置路径,从圆顶点,即-π/2处开始,用CAShapeLayer画出子扇区,设置好颜色和半径就完成了。

2.核心代码

CGFloat startAngle = -M_PI_2;
    for (int i = 0; i < self.pieDataArray.count; i++) {
        NSString *num = self.pieDataArray[i];
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius startAngle:startAngle endAngle:startAngle + [num floatValue] / total * M_PI * 2 clockwise:YES];
        [path addLineToPoint:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2)];// 圆心
        [[self colorWithHexString:self.colorArray[i]] setStroke];
        [[self colorWithHexString:self.colorArray[i]] setFill];
        [path stroke];
        [path fill];
        
        CAShapeLayer *layer = [CAShapeLayer layer];
        layer.path = path.CGPath;
        layer.strokeColor = [UIColor whiteColor].CGColor; // 描边颜色
        layer.fillColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 背景填充色
        [pieView.layer addSublayer:layer];
        
        startAngle = startAngle + [num floatValue] / total * M_PI * 2 ;
    }

为了实现动画效果,需要在画出子扇区之前,设置一层遮罩,同样也可以用UIBezierPath和CAShapeLayer来实现,并将这层遮罩设置为圆

// 背景
    UIBezierPath *bgPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius / 2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
    CAShapeLayer *bgLayer = [CAShapeLayer layer];
    bgLayer.fillColor = [UIColor clearColor].CGColor;
    bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
    bgLayer.strokeStart = 0;
    bgLayer.strokeEnd = 1;
    bgLayer.zPosition = 1;
    bgLayer.lineWidth = radius;
    bgLayer.path = bgPath.CGPath;

并且务必在设置动画之前设置遮罩

pieView.layer.mask = bgLayer;

然后添加上动画

// 动画
    CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    strokeAnimation.fromValue = @0;// 起始值
    strokeAnimation.toValue = @1;// 结束值
    strokeAnimation.duration = 1;// 动画持续时间
    strokeAnimation.repeatCount = 1;// 重复次数
    strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    strokeAnimation.removedOnCompletion = YES;
    [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];

这样一个单层饼图就完成了。

多层饼图的适用环境,内层饼图数据与外层饼图数据有包含关系,比如内层中的一工区包含外层的一小队、二小队等。

多层饼图的内层实现和单层饼图类似,外层实现是只利用UIBezierPath画一个圆弧轨迹,并设置线宽lineWidth和内层没有重合部分就行了。

二、柱状图

1.实现思路

首先找到数据中的最大值,向上取整十或整百或整千并设置为Y轴最大值,然后在Y轴右侧放置一个scrollView(当数据超过5组时可以滚动),然后根据传入数据的分组标题,设置X轴和X轴分组标题,然后根据每个具体数据的值,算出柱顶点坐标,然后用UIBezierPath来设置柱路径,再画出柱子

2.核心代码

NSString *num = self.dataArray[i];
        CGFloat columnHeight = (self.yAxisView.bounds.size.height - 20) * [num intValue] / maxNum;
        UIBezierPath *columnPath = [UIBezierPath bezierPath];
        [columnPath moveToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height)];
        [columnPath addLineToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height - columnHeight)];
        columnPath.lineWidth = [self.columnWidth intValue];
        [[self colorWithHexString:self.columnColor] setStroke];
        [[self colorWithHexString:self.columnColor] setFill];
        [columnPath stroke];
        [columnPath fill];
        /*
            在这后面完成柱子的绘制(分渐变色和非渐变色讨论)
        */

当柱子不是渐变色时,用CAShapeLayer,代码如下:

CAShapeLayer *columnLayer = [CAShapeLayer layer];
            columnLayer.path = columnPath.CGPath;
            columnLayer.strokeColor = [self colorWithHexString:self.columnColor].CGColor;// 描边颜色
            columnLayer.fillColor = [self colorWithHexString:self.columnColor].CGColor;
            columnLayer.lineWidth = [self.columnWidth intValue];
            [dataView.layer addSublayer:columnLayer];

当柱子是渐变色时,用CAGradientLayer,代码如下:

CAGradientLayer *columnGradientLayer = [CAGradientLayer layer];
            columnGradientLayer.frame = CGRectMake(dataView.bounds.size.width / 2 - [self.columnWidth intValue] / 2, dataView.bounds.size.height - columnHeight, [self.columnWidth intValue], columnHeight);
            columnGradientLayer.colors = @[(__bridge id)[self colorWithHexString:self.columnGradientColorArray[0]].CGColor,
                                           (__bridge id)[self colorWithHexString:self.columnGradientColorArray[1]].CGColor];
            columnGradientLayer.locations = @[@(0.0),@(1.0)];// 颜色变化位置
            columnGradientLayer.startPoint = CGPointMake(0, 0);
            columnGradientLayer.endPoint = CGPointMake(0, 1);
            [dataView.layer addSublayer:columnGradientLayer];

同样的,如果需要实现柱子自下而上的动画,也需要设置一个背景来遮罩

UIBezierPath *bgPath = [UIBezierPath bezierPath];
        [bgPath moveToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height)];
        [bgPath addLineToPoint:CGPointMake(dataView.bounds.size.width / 2, 0)];
        bgPath.lineWidth = groupWidth;
        CAShapeLayer *bgLayer = [CAShapeLayer layer];
        bgLayer.fillColor = [UIColor clearColor].CGColor;
        bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
        bgLayer.strokeStart = 0;
        bgLayer.strokeEnd = 1;
        bgLayer.zPosition = 1;
        bgLayer.lineWidth = groupWidth;
        bgLayer.path = bgPath.CGPath;
        dataView.layer.mask = bgLayer;

再加上动画

// 动画
        CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        strokeAnimation.fromValue = @0;// 起始值
        strokeAnimation.toValue = @1;// 结束值
        strokeAnimation.duration = 1;// 动画持续时间
        strokeAnimation.repeatCount = 1;// 重复次数
        strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        strokeAnimation.removedOnCompletion = YES;
        [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];

一个单柱的柱状图就实现了,如果要实现多柱(最多4柱,因为多了不好看,嘻嘻~),也不复杂,大概实现思路和单柱一样,只有一点就是需要调整每组柱体的x坐标在每组的中点即可。

三、折线图

1.实现思路

单纯的折线图实现思路起始很简单,就是在背景上利用循环,算出每个数据的点坐标,然后用UIBezierPath和CAShapeLayer来画出每个点之前的直线就行了。

然而,如果要把折线换成平滑的曲线,这就不好实现了,需要用到UIBezierPath的addCurveToPoint: controlPoint1: controlPoint2:方法了,除了需要传入数据点,还需要传入两个控制点,因为贝塞尔曲线是利用两个控制点来确定一段曲线路径的(大致内容参考自:https://www.jianshu.com/p/c883fbf52681,感谢大佬的分享),但是我依然不知道这两个控制点怎么来确定,毕竟这太高数了(参考自:https://wenku.baidu.com/view/c790f8d46bec0975f565e211.html),我又在网上搜了一下,有现成的(原谅我这个白嫖党)https://www.jianshu.com/p/c33081adce28(再次感谢大佬),于是乎借(cmd+c)鉴(cmd+v)来用。在曲线找点开始之前,先另外创建一个可变数组(NSMutableArray)pointArray,先在这个数组第一个元素的位置保存上原点(0,0)的坐标,用来确定第一段曲线,然后将数据(此时已经转化成CGPointValue)挨个存入pointArray,最后再加上曲线末端向右偏移半个dataView的宽度的距离在x轴上的坐标,用来确定最后一段曲线。最后用CAShapelayer把曲线画出来。

2.核心代码

单纯的折线时

UIBezierPath *dataPath = [UIBezierPath bezierPath];
    dataPath.lineWidth = self.lineWidth;
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
    [dataPath stroke];
    [dataPath fill];
    for (int i = 0; i < self.dataArray.count; i++) {
        // 具体数据
        NSString *num = self.dataArray[i];
        CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
        [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
    }
    CAShapeLayer *dataLayer = [CAShapeLayer layer];
    dataLayer.path = dataPath.CGPath;
    dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
    dataLayer.fillColor = nil;
    dataLayer.lineWidth = self.lineWidth;
    [self.dataView.layer addSublayer:dataLayer];

平滑曲线时

UIBezierPath *dataPath = [UIBezierPath bezierPath];
    dataPath.lineWidth = self.lineWidth;
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
    [dataPath stroke];
    [dataPath fill];

    [self.pointArray removeAllObjects];
    // 起始点
    [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
    CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
    for (int i = 0; i < self.dataArray.count; i++) {
        NSString *num = self.dataArray[i];
        CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
        [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)]];
    }

    // 添加结束点
        [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
        for (int i = 0; i < self.dataArray.count - 1; i++) {
            CGPoint p1 = [self.pointArray[i] CGPointValue];
            CGPoint p2 = [self.pointArray[i+1] CGPointValue];
            CGPoint p3 = [self.pointArray[i+2] CGPointValue];
            CGPoint p4 = [self.pointArray[i+3] CGPointValue];
            if (i == 0) {
                if (self.isFillWithColor) {
                    [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
                    [dataPath addLineToPoint:p2];
                } else {
                    [dataPath moveToPoint:p2];
                    [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
                }
            }
            [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
    CAShapeLayer *dataLayer = [CAShapeLayer layer];
    dataLayer.path = dataPath.CGPath;
    dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
    dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
    dataLayer.lineWidth = self.lineWidth;
    [self.dataView.layer addSublayer:dataLayer];

其中,曲线控制点的计算方法getControlPointOfBezierPath: andPointx0:andy0: x1: andy1: x2: andy2: x3:andy3实现为

/**
 传入四个点求两个控制点 (画2,3之间的曲线,需要传入1,2,3,4的坐标)
 参考自:https://www.jianshu.com/p/c33081adce28
 实在是看球不懂
 */
- (void)getControlPointOfBezierPath:(UIBezierPath *)bezierPath
                         andPointx0:(CGFloat)x0 andy0:(CGFloat)y0
                                 x1:(CGFloat)x1 andy1:(CGFloat)y1
                                 x2:(CGFloat)x2 andy2:(CGFloat)y2
                                 x3:(CGFloat)x3 andy3:(CGFloat)y3 {
    CGFloat smooth_value = 0.6;
    CGFloat ctrl1_x;
    CGFloat ctrl1_y;
    CGFloat ctrl2_x;
    CGFloat ctrl2_y;
    CGFloat xc1 = (x0 + x1) /2.0;
    CGFloat yc1 = (y0 + y1) /2.0;
    CGFloat xc2 = (x1 + x2) /2.0;
    CGFloat yc2 = (y1 + y2) /2.0;
    CGFloat xc3 = (x2 + x3) /2.0;
    CGFloat yc3 = (y2 + y3) /2.0;
    CGFloat len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
    CGFloat len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
    CGFloat len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
    CGFloat k1 = len1 / (len1 + len2);
    CGFloat k2 = len2 / (len2 + len3);
    CGFloat xm1 = xc1 + (xc2 - xc1) * k1;
    CGFloat ym1 = yc1 + (yc2 - yc1) * k1;
    CGFloat xm2 = xc2 + (xc3 - xc2) * k2;
    CGFloat ym2 = yc2 + (yc3 - yc2) * k2;
    ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
    ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
    ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
    ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
    
    [bezierPath addCurveToPoint:CGPointMake(x2, y2) controlPoint1:CGPointMake(ctrl1_x, ctrl1_y) controlPoint2:CGPointMake(ctrl2_x, ctrl2_y)];
}

当线条下面部分需要填充颜色时,需要在path里添加起始点在X轴上的投影的点坐标和结束点在X轴上的投影的点坐标,以保证路径是个闭合的图形,然后设置CAShapeLayer的fillColor(填充色)就可以了,完整判断填充色和平滑曲线的代码如下

UIBezierPath *dataPath = [UIBezierPath bezierPath];
    dataPath.lineWidth = self.lineWidth;
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
    [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
    [dataPath stroke];
    [dataPath fill];
    
    [self.pointArray removeAllObjects];
    // 起始点
    [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
    
    CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
    for (int i = 0; i < self.dataArray.count; i++) {
        // 具体数据
        NSString *num = self.dataArray[i];
        CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
        if (self.isSmooth) {// 是否为平滑曲线
            [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)]];
        } else {
            if (i == 0) {
                if (self.isFillWithColor) {
                    [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
                    [dataPath addLineToPoint:CGPointMake(groupWidth / 2, pointHeight)];
                } else {
                    [dataPath moveToPoint:CGPointMake(groupWidth / 2, pointHeight)];
                }
            } else if (i == self.dataArray.count - 1) {
                [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
                if (self.isFillWithColor) {
                    [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, self.dataView.bounds.size.height)];
                }
            } else {
                [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
            }
        }
    }
    
    if (self.isSmooth) {
        // 添加结束点
        [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
        for (int i = 0; i < self.dataArray.count - 1; i++) {
            CGPoint p1 = [self.pointArray[i] CGPointValue];
            CGPoint p2 = [self.pointArray[i+1] CGPointValue];
            CGPoint p3 = [self.pointArray[i+2] CGPointValue];
            CGPoint p4 = [self.pointArray[i+3] CGPointValue];
            if (i == 0) {
                if (self.isFillWithColor) {
                    [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
                    [dataPath addLineToPoint:p2];
                } else {
                    [dataPath moveToPoint:p2];
                    [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
                }
            }
            [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
        }
        if (self.isFillWithColor) {
            [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * (self.dataArray.count - 1), self.dataView.bounds.size.height)];
//            [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
        }
    }
    
    CAShapeLayer *dataLayer = [CAShapeLayer layer];
    dataLayer.path = dataPath.CGPath;
    if (self.isFillWithColor) {
        dataLayer.strokeColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
        dataLayer.fillColor = [self colorWithHexString:self.fillColor  andAlpha:self.fillAlpha].CGColor;
    } else {
        dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
        dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
    }
    dataLayer.lineWidth = self.lineWidth;
    [self.dataView.layer addSublayer:dataLayer];

和之前两个图表相同,如果需要动画就要添加上背景遮罩

UIBezierPath *bgPath = [UIBezierPath bezierPath];
    [bgPath moveToPoint:CGPointMake(0, self.dataView.bounds.size.height / 2)];
    [bgPath addLineToPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height / 2)];
    bgPath.lineWidth = self.dataView.bounds.size.height;
    CAShapeLayer *bgLayer = [CAShapeLayer layer];
    bgLayer.fillColor = [UIColor clearColor].CGColor;
    bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
    bgLayer.strokeStart = 0;
    bgLayer.strokeEnd = 1;
    bgLayer.zPosition = 1;
    bgLayer.lineWidth = self.dataView.bounds.size.height;
    bgLayer.path = bgPath.CGPath;
    self.dataView.layer.mask = bgLayer;

加上动画

// 动画
    CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    strokeAnimation.fromValue = @0;// 起始值
    strokeAnimation.toValue = @1;// 结束值
    strokeAnimation.duration = 1;// 动画持续时间
    strokeAnimation.repeatCount = 1;// 重复次数
    strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    strokeAnimation.removedOnCompletion = YES;
    [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];

一个单条折线图就完成了,如果需要多条折线图,实现方式也和实现单条类似,只是需要解析的数据数组是个二维数组,里面每个元素都是一条线的数据,外层数组有多少个元素就有多少条线,用循环绘制就可以了。

四、结束语

时间仓促,有许多不完善的地方,还请海涵,有什么问题可以联系我

Demo下载地址:https://download.csdn.net/download/guchuang2599/11179546

Github地址:https://github.com/MichaelJackchuang/GCChart 如果觉得不错就给个star吧!谢谢

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图 的相关文章

  • 使用线程安全单例初始化代码时代码执行停止

    为了利用全局变量和方法 我实现了 Singleton 作为一种健康的编码实践 我跟着苹果文档 http www johnwordsworth com 2010 04 iphone code snippet the singleton pat
  • XCUITest - 无法合成事件:无法计算按钮的命中点

    我想测试按钮的点击行为 执行button tap 时 测试失败 XCTContext runActivity named Validate reply click activity in let button App buttons mat
  • iOS 13中,什么时候保存数据?

    iOS 13 中的场景支持和多窗口使何时保存数据的问题变得复杂 现场代表sceneDidEnterBackground可能看起来是一个相当不错的地方 但有时它还不够 如果您的场景位于最前面并且用户转到应用程序切换器并终止您的应用程序 您将得
  • iOS - 自动调整 CVPixelBufferRef 的大小

    我正在尝试裁剪和缩放CMSampleBufferRef基于用户的输入 基于ratio 下面的代码采用 CMSampleBufferRef 将其转换为 CVImageBufferRef 并使用 CVPixelBuffer 根据其字节裁剪内部图
  • 使用 MapBox Android SDK 进行离线图块缓存

    我有一个使用 iOS 平铺缓存技术的工作 iOS 原型 如下所示 Objective C 代码 RMTileCache tileCache RMTileCache alloc initWithExpiryPeriod 0 tileCache
  • 清空 Firebase DatabaseReference 不会停止观察,这绝对正确吗?

    In the Firebase 太棒了 你做这个 var r1 DatabaseReference nil 然后这个 r1 Database database reference withPath score bucks r1 observ
  • iOS App Today 扩展未上传到物理设备

    我正在为我的应用程序创建一个今日小部件http budgt ch http budgt ch因为一些用户要求快速访问关键功能 初步 扩展在 iOS 模拟器上运行良好 安装如下 1 安装最新的容器应用程序 2 安装以 今天 为容器的扩展 但是
  • 是否可以在无需升级 iOS 企业应用程序的情况下更新配置文件?

    新生成的配置文件似乎不再与同一应用程序的旧版本兼容 新应用程序确实适用于新配置文件 但是我们不想升级链接到旧版本后端且并非全部与最新应用程序兼容的所有应用程序 我们确实需要尽快更新配置文件 以保持旧应用程序正常运行 我们之前已经这样做过 但
  • 如何在 swift 4 中进行两个并发 API 调用

    预先感谢您的帮助 我有两个 API 调用 都是并发的 任何调用都可以先成功 我不想按顺序调用 在两个调用成功后 我必须停止我的活动指示器并重新加载我的 tableView 这是我的代码 但我不知道这是正确的方法 也不知道如何重新加载我的 t
  • 显示不带字母的数字键盘

    iOS 默认数字键盘中是否有隐藏数字下方字母的选项 对于某些电话语言 键盘显示时不带字母 抱歉 你所要求的是不可能的 这取决于键盘语言 只有用户可以更改键盘语言 我希望这能帮到您
  • iOS:调用 Objective-C 方法的处理开销是多少?

    我正在编写一些实时音频处理代码 该代码将在音频单元的渲染回调中执行 该线程处于系统识别的最高优先级 Apple 指示最大限度地减少此调用中进行的处理量 他们的建议之一是避免 Objective C 方法调用 But why 调用 Objec
  • UIPickerView - 对多行行使用自定义视图 - 需要布局建议

    我有一个 UIPickerView 它将为用户显示项目列表 我希望每个项目都显示为多行文本 每行使用不同的字体大小 一个粗略的模型如下所示 这将允许显示比默认 UIPickerView 的单行所能容纳的更多文本 bdesham 指出我在 U
  • 如何将渐变应用于 iOS Swift 应用程序的背景视图

    我正在尝试应用渐变作为视图 故事板的主视图 的背景颜色 代码运行 但没有任何变化 我正在使用 xCode Beta 2 和 Swift 这是代码 class Colors let colorTop UIColor red 192 0 255
  • 退出我的应用程序后未显示蓝色横幅“您的应用程序正在使用您的位置”

    我的应用程序在后台模式下使用核心位置 当应用程序处于后台模式并定期发送 GPS 坐标时 不会显示蓝色横幅 您的应用程序正在使用您的位置 例如谷歌地图应用程序 知道我可能错过了什么吗 要显示蓝色条 您应该 1 启用Background Loc
  • Swift - 本地通知不会被触发

    我正在 Swift 3 中编码 我只是想发送通知now没有任何延迟或间隔 然而 通知永远不会被触发 这是我的代码 视图控制器代码 import UserNotifications class HomeViewController UIVie
  • 在 Android 上使用 opus 剪辑从 IOS 发送的声音

    我正在 IOS 中从 audioUnit 录制音频 用 opus 编码字节并通过 UDP 将其发送到 android 端 问题是播放的声音有点削波 我还通过将原始数据从 IOS 发送到 Android 来测试声音 效果非常完美 我的 Aud
  • 如何在 iOS 中查找蓝牙音频设备

    好的 我正在开发一个有趣的项目 该项目有一个障碍 我需要为我的 iOS 应用程序启用蓝牙音频支持 我遇到的障碍是我什至无法开始获取已连接的蓝牙音频设备的列表 即使我的 iPhone 5S 可以识别我的耳机 大约 3 4 岁的耳机 LG HB
  • 当我从我转向的视图控制器返回时,为什么我的 UITableView 的格式完全出错了?

    我有一个UITableView使用自定义单元格 其中有一些标签可以动态决定单元格的高度 当我点击一个单元格并转到一个新的视图控制器时 返回后所有单元格的格式完全混乱 我无法弄清楚是什么导致了它 这是细胞通常的样子 我对它们设置了一些非常基本
  • 如何建立辅助NSSortDescriptor排序键?

    我已成功按排序键对数据进行排序lastName 但我想知道如何排序lastName 然后由firstName 这是我用来排序的代码lastName NSSortDescriptor sortDescriptor NSSortDescript
  • UITableview 中的水平和垂直滚动[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 I want to make a lineup for a festival You can see what I want to a

随机推荐

  • VMware部署Debian系统

    前面在手机和平板上安装了UserLAnd软件 xff0c 初步实现了随身携带Linux系统的小目标 但是前面也提到了目前存在一个小问题 xff0c 那就是没有办法远程登录 xff0c 简单调整了一下还没解决 xff0c 看来还是要简单学习一
  • Openstack关于Regions和Availability Zones

    声明 xff1a 本博客欢迎转发 xff0c 但请保留原作者信息 内容系本人学习 研究和总结 xff0c 如有雷同 xff0c 实属荣幸 xff01 原文地址 xff1a http blog csdn net gtt116 在AWS中有Re
  • Manjaro 安装搜狗输入法

    经历了长时间搜索和实践 xff0c 我终于安装好了搜狗输入法 xff0c 基本套路就还是按照大多数博客介绍的命令行装的 xff1a sudo pacman S fcitx im sudo pacman S fcitx configtool
  • layui:弹窗跨域问题 Uncaught DOMException: Blocked a frame with origin

    在日常开发中经常出现A系统调用B系统的相关功能 xff0c 在B系统中进行layer弹窗时 xff0c 提示错误信息 Uncaught DOMException xff0c 经过查询网上资料 xff0c 发现是跨域错误 仔细检查代码 xff
  • CentOS安装最新稳定版Jenkins

    文章目录 1 Java版本兼容列表2 JDK安装3 Jenkins安装3 1 定义Jenkins RPM仓库3 2 进行安装 4 Jenkins启动4 1 指定Java程序4 2 相关命令 5 FAQ5 1 目录介绍5 2 AWT is n
  • Codeforces Global Round 21参考代码

    Codeforces Global Round 21 A xff1a include lt iostream gt include lt algorithm gt include lt cstdio gt include lt cstrin
  • 有设计才艺的小伙伴千万不要错过GIMP

    GIMP是一个非常好的位图设计软件 xff01 支持LInux系统 xff0c Windows系统 xff0c Mac xff0c GIMP一直陪着我从Windows转到Linux xff0c 直到现在还在用 个人感觉比PhotoShop强
  • python下载

    python下载 1 打开python官网 网址 xff1a python org 1 1按照对应的操作系统选择 1 2下滑找到3 10 0 版本根据电脑配置选择64位或者32位 一般选择左列的稳定发行版 注意 xff0c 这里有embed
  • Android 捕获主线程异常崩溃

    一般情况下我们想要捕获全局异常会调用Thread setDefaultUncaughtExceptionHandler方法 xff1b 这个方法虽然能捕获所有线程的异常 xff0c 但如果是主线程发生未捕获异常 xff0c APP虽然不会崩
  • 使用cmake编译一段代码时出现VS2015 The C/CXX compiler identification is unknown

    打开CmakeError log 里面有如下错误 xff1a D Program Files Microsoft Visual Studio 14 0 VC bin x86 amd64 link exe ERRORREPORT QUEUE
  • Ubuntu安装VirtualBox6.1,报错依赖于libqt5opengl5...

    自己在安装Vbox6 1时遇到依赖问题 xff0c 多次尝试无法解决 xff0c 最后找到以下解决方法 由于网上看到的很多方法并不能解决问题 xff0c 这里将原文做转载 xff0c 希望能帮助到更多的人 1 方法一 xff1a 从Ubun
  • Debian 10(buster) 更换可用的国内软件源

    由于Debian 10 xff08 buster xff09 还比较新 xff0c 有很多源都使用不了 xff0c 有的还连接不上 xff0c 以下是亲自试过可以使用的源 xff0c 需要的小伙伴可以试试 163源 deb cdrom De
  • ubuntu 下搭建 Jenkins 并配置部署环境

    转载 xff1a https www cnblogs com shuoer p 9471839 html 前言 xff1a 因为要搭建Jenkins xff0c 试了很多办法都不行 xff0c 后来找到这篇博客装好了 xff0c 分享下 x
  • 批处理文件(.dat/.cmd)打开多个文件

    在window下 xff0c 有时候经常需要一次性打开多个文件 xff0c 如果都在一个目录下还好 xff0c 但是如果需要打开的文件分布在各个地方 xff0c 逐一打开还是挺麻烦的 通过批处理可以偷下懒 废话少说 xff0c 例文如下 x
  • STC 定时器/计数器2 操作详解 (基于STC89C52RC参考文档)

    一 认识STC定时器2 T2 STC 定时器2 xff08 即T2 xff09 是一个16位定时 计数器 通过设置特殊功能寄存器T2CON中的C T2位 xff0c 可将其作为定时器或计数器 xff08 特殊功能寄存器T2CON的描述如表1
  • 第五周作业 C题

    C题 平衡字符串 题目描述 xff1a 一个长度为 n 的字符串 s xff0c 其中仅包含 Q W E R 四种字符 如果四种字符在字符串中出现次数均为 n 4 xff0c 则其为一个平衡字符串 现可以将 s 中连续的一段子串替换成相同长
  • 第八周作业 B题

    B 猫猫向前冲 题目描述 xff1a 众所周知 xff0c TT 是一位重度爱猫人士 xff0c 他有一只神奇的魔法猫 有一天 xff0c TT 在 B 站上观看猫猫的比赛 一共有 N 只猫猫 xff0c 编号依次为1 xff0c 2 xf
  • Linux安装Git和GitLab,最新教程,细到极致

    大家早上好呀 xff0c 又到了周末了 xff0c 心情很舒服 摸鱼了一上午 xff0c 想要写点东西 今天给大家带来的是 xff0c git和GitLab的安装 快速定位到Gitlab安装 话不多说 xff0c 开始吧 1 创建git文件
  • Ubuntu安装搜狗输入法无论如何就是找不到的解决方法///Ubuntu怎么安装搜狗输入法///Ubuntu怎么输入中文///Ubuntu搜狗输入法怎么修改皮肤

    我刚装上ibus的时候 xff0c 感觉一点也不好用 xff0c 于是就换成了fcitx打算安装搜狗输入法for Linux xff0c 结果各种方法都试过了 xff0c 无论如何都找不到搜狗输入法 xff0c 我偶然把fcitx5换成了f
  • iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图

    话不多说 xff0c 先来看看效果 xff1a 1 饼图 扇形图 2 柱状图 3 折线图 样子粗糙 xff0c 见笑了 现在来看看实现过程 一 饼图 扇形图 1 实现思路 实现思路其实很简单 xff0c 首先算传入数据数组的数据总和 xff