【问题标题】:Using a gradient along a path沿路径使用渐变
【发布时间】:2011-09-22 01:29:32
【问题描述】:

我正在尝试使用 Android Path 类创建“发光”效果。但是,渐变不会被扭曲以适应路径。相反,它只是显示在它的“上方”并剪裁到路径的笔划。使用方形路径,下图显示了我的意思:

相反,它应该看起来更像这样:

换句话说,渐变跟随路径,特别是根据 CornerPathEffect 中设置的半径环绕拐角。

以下是代码的相关部分:

paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(20);
paint.setAntiAlias(true);
LinearGradient gradient = new LinearGradient(30, 0, 50, 0,
    new int[] {0x00000000, 0xFF0000FF, 0x00000000}, null, Shader.TileMode.MIRROR);
paint.setShader(gradient);
PathEffect cornerEffect = new CornerPathEffect(10);
paint.setPathEffect(cornerEffect);
canvas.drawPath(boxPath, paint);

有什么想法吗?


另一种选择是在定义笔触宽度时获得“软边画笔”效果。我已经尝试过 BlurMaskFilters,但它们会产生均匀的模糊,而不是从不透明到透明的过渡。有谁知道这是否可能?

【问题讨论】:

    标签: android graphics path gradient shader


    【解决方案1】:

    用软笔刷位图绘图怎么样?使用 Photoshop 等图像编辑软件制作一个不透明度向外径向减小的软圆形画笔。另存为drawable,将其加载到位图中并沿路径均匀地绘制。用白色画笔制作位图。这样,您可以使用 PorterDuffColorFilter 简单地将给定颜色(此处为蓝色)与位图相乘。

    brush1=BitmapFactory.decodeResource(getResources(), R.drawable.brush_custom_one);
    //This contains radially decreasing opacity brush
    porter_paint.setColorFilter(new PorterDuffColorFilter(paint.getColor(), Mode.MULTIPLY));
    for (int i=1;i<matrix.size();i++) {
    //matrix contains evenly spaced points along path 
    Point point = matrix.get(matrix.get(i));
    canvas.drawBitmap(brush1, point.x,point.y, porter_paint);}
    

    使用的画笔是(在那儿): 最终结果为:

    【讨论】:

    • 这是另一种可能相当不错的解决方案。下次我需要做这样的事情时,我会调查一下。 (此主题已有 2 年历史)
    • 你能分享一下画笔吗(brush_custom_one)
    【解决方案2】:

    原来有一种愚蠢明显的方法可以做到这一点。只需重复使用相同的路径,并在每个绘图通道上调整笔触宽度和 alpha。示例代码:

    float numberOfPasses = 20;
    float maxWidth = 15;
    for (float i = 0; i <= numberOfPasses; i++){
        int alpha = (int) (i / numberOfPasses * 255f);
        float width = maxWidth * (1 - i / numberOfPasses);
    
        paint.setARGB(alpha, 0, 0, 255);
        paint.setStrokeWidth(width);
        canvas.drawPath(path, paint);
    }
    

    请参阅下面的结果示例。左边的路径是用这个方法画的,右边的路径,为了比较,用maxWidth和255 alpha单笔画。

    这主要是有效的。有两个问题:

    • 渐变没有应有的平滑。这是因为在前一个通道上绘制的每个通道都会导致 alpha 建立得太快,在最后一笔之前达到 255。对int alpha = (int) (i / numberOfPasses * 125f); 行进行一些试验(注意更改为 125f 而不是 255f)会有所帮助。

    • 路径看起来像是在拐角的内侧被“切割”了。可能是应用了CornerPathEffect 的一些结果。

    【讨论】:

    • 嘿,史蒂夫——事实上,上周我在长途驾驶中感到无聊时也产生了同样的想法;我现在踢自己,因为后来不记得在这里提到它!不过,我很高兴您尝试了它并发现它有效,并且了解您遇到的问题很有趣。感谢您分享您的代码。我将在我的 SVG 解析器中添加类似的内容,并且我可能会定义我自己的自定义命名空间 XML 标记以在特定路径上触发此功能。出色的工作 - +1!
    • alpha 应该是255/numberOfPasses,而不是乘以i
    【解决方案3】:

    如果我理解正确的话,您想要做的是让渐变有效地形成笔触的“画笔”。

    正是我最近也试图实现的,但据我所知,API 没有提供任何直接的方法来做到这一点。我最近创建了一个 SVG 到 Android Canvas 转换器类,所以我最近也在 Inkscape 工作了很多。所以,当我研究它时,我想知道它是否可以在 Inkscape 中完成。然而,即使在 Inkscape 中,这也是一件非常重要的事情。经过一番搜索,我最终发现了这张沿路径应用渐变的图像,以及下面教程的下载链接:

    http://www.flickr.com/photos/35772571@N03/3312087295/

    当时我个人尝试做的是创建一些半圆形,其中路径是一种霓虹灯而不是平面颜色。就 Android API 和 SVG 标准而言,似乎唯一的方法是创建一个完全以圆为中心的径向渐变,并将一系列色标定位在正确的位置。做起来很棘手,我当然不知道你怎么把它做成一个正方形的形状。

    很抱歉,这有点像“我也做不到”,而不是有用的答案!我会感兴趣地关注这一点,因为我也很想知道一种“软刷”效果的解决方案。

    【讨论】:

    • 嗯,很高兴知道我不是唯一一个努力寻找解决方案的人:P 我能想到的唯一剩下的解决方案是写一个数学公式的野兽,给出一个path 在它旁边创建额外的路径。然后您手动绘制几次不同的Paints 降低不透明度。这听起来像是个大杂烩,但我想我在某处读到过,Android 团队对 Android Market 的图形使用了类似的方法。
    • 原来有一种愚蠢的明显方法 - 如果您仍然感兴趣,请参阅下面的答案。另外,我偶然发现了我在之前的评论中提到的关于 Android 团队如何在 Android 市场上大放异彩的文章:pushing-pixels.org/2010/12/15/meet-the-green-goblin-part-3.html
    【解决方案4】:

    绘制渐变比跟随路径要复杂得多。 所以我建议你使用一些已经完成的库,而不是为你制作。 一个可以是Sc-Gauges

    有一些有用的类,而不是你可以用来实现你的目标。

    首先包含库:

    dependencies {
        ...
        compile 'com.github.paroca72:sc-gauges:3.0.7'
    }
    

    使用画布创建图像或您想要的内容后:

    <ImageView
          android:id="@+id/image"
          android:layout_width="match_parent"
          android:layout_height="match_parent" 
    />
    

    现在是代码:

        // Dimensions
        int padding = 24;
        Rect drawArea = new Rect(padding, padding, 700 - padding, 500 - padding);
    
        // Get the main layout
        ImageView imageContainer = (ImageView) this.findViewById(R.id.image);
        assert imageContainer != null;
    
        // Create a bitmap and link a canvas
        Bitmap bitmap = Bitmap.createBitmap(
                drawArea.width() + padding * 2, drawArea.height() + padding * 2,
                Bitmap.Config.ARGB_8888
        );
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.parseColor("#f5f5f5"));
    
        // Create the path building a bezier curve from the left-top to the right-bottom angles of
        // the drawing area.
        Path path = new Path();
        path.moveTo(drawArea.left, drawArea.top);
        path.quadTo(drawArea.centerX(), drawArea.top, drawArea.centerX(), drawArea.centerY());
        path.quadTo(drawArea.centerX(), drawArea.bottom, drawArea.right, drawArea.bottom);
    
        // Feature
        ScCopier copier = new ScCopier();
        copier.setPath(path);
        copier.setColors(Color.RED, Color.GREEN, Color.BLUE);
        copier.setWidths(20);
        copier.draw(canvas);
    
        // Add the bitmap to the container
        imageContainer.setImageBitmap(bitmap);
    

    结果如下:

    代码的第一部分仅用于创建绘制位图。 您感兴趣的是使用 ScCopier 的第二部分。 只需给出路径、颜色和搭配即可。

    请注意,您在视图中可以使用onDraw 直接在视图画布上进行绘制。

    这个库可以用来创建各种仪表。 如果你想看看这个网站ScComponents有一些免费的而不是仪表组件。

    【讨论】:

    • 所以,我有这个任务,我有这样的路径:直线,90 度圆弧,直线。这条路径的宽度为 2dp。并且它本身需要有渐变。我想你只是为我节省了很多精力。因为我的解决方案是:线性渐变+滑动渐变+线性渐变。我需要以某种方式计算中间颜色。谢谢大佬。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多