26

我正在使用两种不同的颜色创建不同的自定义视图。根据我的应用程序功能,用户将在屏幕上拖动这些对象,拖动对象时会相互重叠。我想区分重叠区域,如何设置重叠区域的组合颜色。看下图。在这里,我使用画布来创建那些自定义视图,两个圆圈是两个不同的视图。

在此处输入图像描述

编辑: 如果我使用 opacity 128 我能够看到背景颜色,但我想要重叠对象颜色的组合颜色。

4

6 回答 6

20

您正在寻找的颜色混合有时称为直观颜色混合RYB颜色系统:

红豆

在此处输入图像描述 抄送许可证

Nathan Gossett 和 Baoquan Chen引用的这篇论文中关于直观颜色混合算法的引述总结了直观颜色系统的工作原理:

“在这个模型中,红色、黄色和蓝色用作纯原色。红色和黄色混合形成橙色,黄色和蓝色混合形成绿色,蓝色和红色混合形成紫色 [...]。这些是未经训练的观众期望使用儿童颜料获得的颜色 [...]。此外,许多人并不认为白色是所有颜色的混合,而是认为没有颜色(空白画布)。更常见的假设将多种颜色混合在一起会产生浑浊的深棕色。”

RYB 没有在 Android 的混合模式中实现,也不能真正通过混合 alpha/不同的混合模式来模拟。

大多数计算机图形应用程序都使用RGBCMYK颜色空间:

三色卡

在此处输入图像描述抄送许可证

CMY 基于减色法。减色混合意味着,从白色开始,随着我们添加颜色,结果变得更暗。CMYK 用于混合用于在 Photoshop 和 Illustrator 中打印的图像中的颜色。

RGB

在此处输入图像描述 抄送许可证

RGB 基于加色。计算机屏幕上的颜色是使用加色法用光创建的。加色混合从黑色开始,随着添加更多颜色,结果变得更亮并以白色结束。

站点更详细地讨论了 CMYK 和 RGB。

在 RGB 和 CMYK 中,混合蓝色和黄色都不会产生绿色,或者一般来说,直观的颜色混合。在 Android 上实现一个 RYB 颜色系统将是相当复杂的。上面引用的 Nathan Gossett 和 Baoquan Chen 的论文在论文的最后提出了一个用 C 语言实现的算法的解决方案。该算法可以在 Android 上的自定义混合中实现。Drawable.setColorFilter()使用PorterDuffColorfilterwhich extends ColorFilterColorFilterSO 问题中讨论的子类化必须使用 NDK 在本机代码中完成。

CMYK 颜色混合解决方法

如果您有兴趣使用 CMYK 颜色混合作为解决方法,我在下面提供了一个基本示例,说明如何完成。在此示例中,将混合青色圆圈和黄色圆圈以产生绿色相交。

从在 Adob​​e Illustrator 中创建的这些 .png 图像文件开始:

在此处输入图像描述

在此处输入图像描述

十六进制颜色值为 0x00ffff(青色)和 0xffff00(黄色)。

将它们添加到名称为 cyancircle.png 和 yellowcircle.png 的可绘制文件夹中。

如下配置您的 main.xml 布局:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    android:background="#ffffff"
    android:padding="30dp">

<ImageView
    android:id="@+id/bluecircle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/cyancircle">
</ImageView>

<ImageView
    android:id="@+id/yellowcircle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/yellowcircle" 
    android:layout_marginTop="30dp">
</ImageView>     
</RelativeLayout>

创建您的活动:

import android.app.Activity;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.widget.ImageView;

public class PorterDuffTestActivity extends Activity {
/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ImageView yellowCircle = (ImageView)findViewById(R.id.yellowcircle);

        yellowCircle.getDrawable().setColorFilter(0x88ffff00, PorterDuff.Mode.MULTIPLY);
    }
}

输出:

在此处输入图像描述

此方法的限制是顶部形状的 alpha 必须设置为 50%(“0x88ffff00”中的“88”)。对于黄色,这可以很好地工作,但对于其他颜色,alpha 效果可能无法接受(颜色可能看起来是另一种颜色,例如红色变成粉红色,白色背景上的 alpha 值较低)。您最终可以接受哪种混合模式取决于您要使用的颜色集,并且需要进行一些实验。另请注意,背景颜色可能会影响混合模式下圆圈的颜色。在此示例中,背景设置为白色。

于 2012-07-06T04:52:58.233 回答
5

我为 6 个对象做了另一个示例

在此处输入图像描述

关键点:

  1. 对象视图不会覆盖 onDraw 方法,背景也将设置为透明

    设置背景颜色(颜色。透明);

  2. 但是,onDraw 方法将被重命名为 onDrawEx 将从 Overlay View 中调用。

    公共无效 onDrawEx(帆布画布){

  3. 覆盖视图将传递一个自定义画布来绘制。在传递到对象视图之前,它会进行必要的翻译。

        mOverlayView = new View(this){
        @Override
        protected void onDraw(Canvas canvas) {
            Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
            Canvas canvasBitmap = new Canvas(bitmap);
            ViewGroup viewGroup = (ViewGroup)getParent();
            for(int i = 0 ; i < viewGroup.getChildCount()-1;i++){
                ObjectView objectView = (ObjectView) viewGroup.getChildAt(i);
                canvasBitmap.save();
                canvasBitmap.translate(objectView.getTranslationX(), objectView.getTranslationY());
                objectView.onDrawEx(canvasBitmap);
                canvasBitmap.restore();
            }
            canvas.drawBitmap(bitmap, 0, 0, new Paint());
        }
    };
    
  4. 使用 mPaint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 添加颜色。但是所有对象都应该使用像 0xFF000030,0xFF0000C0,0xFF003000,0xFF00C000,0xFF300000,0xC00000 这样的颜色,然后只有所有可能的重叠我们才能得到不同的颜色。这取决于您的最大对象数。

        int k = 0 ;
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x000030<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x003000<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x300000<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    

这里我已经修改为支持版本 8

利用

mPaint.setXfermode(new PixelXorXfermode(0x00000000));

为了

mPaint.setXfermode(new PorterDuffXfermode(Mode.ADD));

我使用布局参数进行翻译。

于 2012-07-07T09:51:54.560 回答
3

我能想到的最简单的解决方案是通过在代码或 xml 中将每个不透明度设置为 0.5 来简单地使用 alpha 通道。然后当颜色重叠时,颜色应该相互淡入。不过,这确实意味着非重叠部分的颜色会有点褪色,并且取决于形状背后的背景,让它们完全透明可能看起来不太好。

于 2012-07-03T15:02:54.977 回答
3

我创建了一个带有两个视图 DemoDrawShapeActivity的示例 Activity,其中在 view2 中我使用 canvas.clipPath 和 canvas.translate

为此,我设置了最低 sdk 版本 4

在此处输入图像描述

protected void onDraw(Canvas canvas) {
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    path2.addCircle(getWidth()/2, getHeight()/2, getWidth()/2, Direction.CCW);
    canvas.drawPath(path2, paint);
    canvas.clipPath(path2);
    canvas.save();
    canvas.translate(-getTranslationX()+view1.getTranslationX(), -getTranslationY()+view1.getTranslationY());

    paint.setColor(Color.BLUE|Color.RED);
    canvas.drawPath(path1, paint);
    canvas.restore();

}

您可以编辑 paint.setColor(Color.BLUE|Color.RED); 根据您的逻辑获得必要的颜色。

我正在使用 setTranslationX setTranslationY 来移动视图。

        public boolean onTouchEvent(MotionEvent event) {
                switch(event.getActionMasked()){
                case MotionEvent.ACTION_UP:
                    touched[0]=touched[1]=false;
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    if(touched[1]){
                        view2.setTranslationX(event.getX()-view2.getWidth()/2);
                        view2.setTranslationY(event.getY()-view2.getHeight()/2);
                    }else if(touched[0]){
                        view1.setTranslationX(event.getX()-view1.getWidth()/2);
                        view1.setTranslationY(event.getY()-view1.getHeight()/2);
                        view2.invalidate();
                    }
                }
                return true;
            }
于 2012-07-06T07:31:05.697 回答
2

我认为您可能希望以混合模式进行绘制。Android 会让你这样做,只要看看这个第一个链接。 Android Canvas 中的复合操作

以下是所有合成选项 http://developer.android.com/reference/android/graphics/PorterDuffXfermode.html

以及来自 Mozilla 的解释 https://developer.mozilla.org/en/Canvas_tutorial/Compositing

于 2012-07-05T15:48:11.473 回答
-1

您可以从中获得帮助-

http://www.learnopengles.com/android-lesson-five-an-introduction-to-blending/

www.pushing-pixels.org/category/android/page/6

于 2012-07-11T07:47:34.330 回答