2014-01-15 34 views
0

我正在开发一个应用程序,它必须在纵向iPhone屏幕上绘制320条垂直渐变线,其中每个渐变线的宽度为1px或2px(非视网膜vs视网膜)。每个渐变线都有1000个位置,每个位置都有唯一的颜色。这1000种颜色(花车)坐在C风格的2D阵列(阵列阵列,1000个颜色的320阵列)如何快速绘制许多渐变线

目前,渐变线绘制在自定义UIView的drawRect方法内的For循环中。我遇到的问题是花费比一秒多的时间循环遍历For循环并绘制全部320行。在那一秒钟内,我有另一个更新颜色数组的线程,但由于它需要一秒以上的绘制时间,我没有看到每一个更新。我看到每第二次或第三次更新。

我使用在我的Android代码,它没有问题绘图640条梯度线完全相同的过程中多次的第二使用SurfaceView(两倍的量)。我的Android应用程序永远不会错过任何更新。

如果您看一下Android代码,它实际上会为两个单独的画布绘制渐变线。数组大小是动态的,可以达到Android手机的横向分辨率宽度的一半(例如1280宽度= 1280/2 = 640行)。由于Android应用足够快,我允许横向模式。即使将数据翻倍为iPhone并绘制到两个单独的画布上,Android代码也会每秒运行多次。具有一半行数的iPhone代码只能绘制到单个上下文中,不能在一秒之内完成。

是否有更快的方式在iPhone上绘制320条垂直渐变线(每个线都有1000个位置)?

是否有硬件加速SurfaceView等价物,可以吸引很多梯度非常快的iOS?

//IPHONE - drawRect method 
int totalNumberOfColors = 1000; 
int i; 
CGFloat *locations = malloc(totalNumberOfColors * sizeof locations[0]); 
for (i = 0; i < totalNumberOfColors; i++) { 
    float division = (float)1/(float)(totalNumberOfColors - 1); 
    locations[i] = i * division; 
} 
CGContextRef ctx = UIGraphicsGetCurrentContext(); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
for (int k = 0; k < 320; k++) { 
    CGFloat * colorComponents = arrayOfFloatArrays[k]; 

    CGGradientRef gradient = CGGradientCreateWithColorComponents(
                   colorSpace, 
                   colorComponents, 
                   locations, 
                   (size_t)(totalNumberOfColors)); 
    CGRect newRect; 
    if (currentPositionOffset >=320) { 
     newRect = CGRectMake(0, 0, 1, CGRectGetMaxY(rect)); 
    } else { 
     newRect = CGRectMake(319 - (k * 1), 0, 1, CGRectGetMaxY(rect)); 
    } 
    CGContextSaveGState(ctx); 
    //NO CLIPPING STATE 
    CGContextAddRect(ctx, newRect); 
    CGContextClip(ctx); 
    //CLIPPING STATE 
    CGContextDrawLinearGradient(
           ctx, 
           gradient, 
           CGPointMake(0, 0), 
           CGPointMake(0, CGRectGetMaxY(rect)), 
           (CGGradientDrawingOptions)NULL); 


    CGContextRestoreGState(ctx); 
    //RESTORE TO NO CLIPPING STATE 
    CGGradientRelease(gradient); 
} 

//ANDROID - public void run() method on SurfaceView 
for (i = 0; i < sonarData.arrayOfColorIntColumns.size() - currentPositionOffset; i++) { 
    Paint paint = new Paint(); 
    int[] currentColors = sonarData.arrayOfColorIntColumns.get(currentPositionOffset + i); 
    //Log.d("currentColors.toString()",currentColors.toString()); 
    LinearGradient linearGradient; 
    if (currentScaleFactor > 1.0) { 
     int numberOfColorsToUse = (int)(1000.0/currentScaleFactor); 

     int tmpTopOffset = currentTopOffset; 
     if (currentTopOffset + numberOfColorsToUse > 1000) { 
      //shift tmpTopOffset 
      tmpTopOffset = 1000 - numberOfColorsToUse - 1; 
     } 
     int[] subsetOfCurrentColors = new int[numberOfColorsToUse]; 
     System.arraycopy(currentColors, tmpTopOffset, subsetOfCurrentColors, 0, numberOfColorsToUse); 
     linearGradient = new LinearGradient(0, tmpTopOffset, 0, getHeight(), subsetOfCurrentColors, null, Shader.TileMode.MIRROR); 
     //Log.d("getHeight()","" + getHeight()); 
     //Log.d("subsetOfCurrentColors.length","" + subsetOfCurrentColors.length); 
    } else { 
     //use all colors 
     linearGradient = new LinearGradient(0, 0, 0, getHeight(), currentColors, null, Shader.TileMode.MIRROR); 
     //Log.d("getHeight()","" + getHeight()); 
     //Log.d("currentColors.length","" + currentColors.length); 
    } 
    paint.setShader(linearGradient); 
    sonarData.checkAndAddPaint(paint); 

    numberOfColumnsToDraw = i + 1; 
} 
//Log.d(TAG,"numberOfColumnsToDraw " + numberOfColumnsToDraw); 
currentPositionOffset = currentPositionOffset + i; 

if (currentPositionOffset >= sonarData.getMaxNumberOfColumns()) { 
    currentPositionOffset = sonarData.getMaxNumberOfColumns() - 1; 
} 

if (numberOfColumnsToDraw > 0) { 
    Canvas canvas = surfaceHolder.lockCanvas(); 
    if (AppInstanceData.sonarBackgroundImage != null && canvas != null) { 
     canvas.drawBitmap(AppInstanceData.sonarBackgroundImage, 0, getHeight()- AppInstanceData.sonarBackgroundImage.getHeight(), null); 
     if (cacheCanvas != null) { 
      cacheCanvas.drawBitmap(AppInstanceData.sonarBackgroundImage, 0, getHeight()- AppInstanceData.sonarBackgroundImage.getHeight(), null); 
     } 

    } 
    for (i = drawOffset; i < sizeToDraw + drawOffset; i++) { 
     Paint p = sonarData.paintArray.get(i - dataStartOffset); 
     p.setStrokeWidth(2); 
     //Log.d("drawGradientLines", "canvas.getHeight() " + canvas.getHeight()); 
     canvas.drawLine(getWidth() - (i - drawOffset) * 2, 0, getWidth() - (i - drawOffset) * 2, canvas.getHeight(), p); 

     if (cacheCanvas != null) { 
      cacheCanvas.drawLine(getWidth() - (i - drawOffset) * 2, 0, getWidth() - (i - drawOffset) * 2, canvas.getHeight(), p); 
     } 

    } 
    surfaceHolder.unlockCanvasAndPost(canvas); 
} 

回答

0

对CG代码无可奉告 - 它已经有一段时间,因为我画的任何梯度 - 但有两点要注意:

  • 你不应该这样做,在drawRect中,因为它被称为很多。绘制成图像并显示它。
  • 没有匹配的malloc自由,所以你像疯了似的泄漏内存。
0

这将有一个学习曲线,但实现这个使用OpenGL ES 2.0。我以前使用过绘制大量渐变的东西,并使用OpenGL ES 2.0和自定义顶点和片段着色器重新实现它。它比使用Core Graphics完成的等效绘图要快得多,所以你可能会看到很大的速度提升。

如果您还不知道任何OpenGL,我会建议您在iOS上找到一些与OpenGL ES 2.0一起使用的教程(必须是2.0,因为这是提供编写自定义着色器的能力)以了解基础知识。一旦你这样做了,你应该能够显着提高你的绘图的性能,超过Android版本的性能,也可能会激励使Android版本使用OpenGL。