如何为两个不同颜色对象的重叠区域设置组合颜色?

时间:2012-07-03 14:06:26

标签: android drawing

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

enter image description here

编辑:如果我使用不透明度128,我可以看到背景颜色,但我想要重叠对象颜色的组合颜色。

6 个答案:

答案 0 :(得分:21)

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

<强> RYB

enter image description here <子> <子> CC license

Nathan Gossett和Baoquan Chen撰写的关于直观颜色混合算法的this论文引用了直观颜色系统的工作原理:

  

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

RYB未在Android的混合模式中实现,并且无法通过混合alpha /不同混合模式来真正模拟。

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

<强> CMYK

enter image description here <子> <子> CC license

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

<强> RGB

enter image description here CC license

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

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

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

CMYK颜色混合解决方法

如果您对使用CMYK颜色混合作为解决方法感兴趣,我已经包含了一个如何在下面完成它的基本示例。在此示例中,将混合青色圆圈和黄色圆圈以产生绿色交叉点。

从Adobe Illustrator中创建的这些.png图像文件开始:

enter image description here

enter image description here

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

将它们添加到名为cyancircle.png和yellowcircle.png的drawable文件夹中。

按如下方式配置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);
    }
}

输出:

enter image description here

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

答案 1 :(得分:5)

我为6个对象做了另一个example

enter image description here

要点:

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

    setBackgroundColor(Color.TRANSPARENT);

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

    public void onDrawEx(Canvas canvas){

  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));
    }
    
  5. 我在modified支持版本8

    使用

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

    代表

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

    我使用layout参数进行翻译。

答案 2 :(得分:3)

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

答案 3 :(得分:3)

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

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

enter image description here

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;
            }

答案 4 :(得分:2)

我认为您可能希望以混合模式进行绘制。 Android会让你这样做,只需看看这个第一个链接。 Composite operations in Android Canvas

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

他们对Mozilla的解释 https://developer.mozilla.org/en/Canvas_tutorial/Compositing

答案 5 :(得分:-1)

你可以从这里得到帮助 -

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

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