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

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

在这里输入图像说明

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

Solutions Collecting From Web of "如何设置两个不同颜色对象重叠区域的组合颜色?"

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

RYB

在这里输入图像说明 CC许可证

Nathan Gossett和Baoquan Chen在本文中对直观颜色混合algorithm的引用总结了直观颜色系统的工作原理:

“在这个模型中,红色,黄色和蓝色用作纯原色,红色和黄色混合形成橙色,黄色和蓝色混合形成绿色,蓝色和红色混合形成紫色,这些是另外,许多人并不认为白色是所有颜色的混合物,而是由于没有颜色(一个空白的canvas),而更常见假设将许多颜色混合在一起会导致泥泞的深褐色。“

RYB没有在Android的混合模式下实现,并不能通过混合alpha /不同的混合模式来模拟。

大多数计算机graphics应用程序使用RGBCMYK色彩空间:

CMYK

在这里输入图像说明 CC许可证

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

RGB

在这里输入图像说明 CC许可证

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

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

无论是RGB还是CMYK,混合蓝色和黄色都会产生绿色,或者一般来说,直观的颜色混合。 在Android上实现一个RYB颜色系统将是相当重要的。 上面引用的Nathan Gossett和Baoquan Chen的论文提出了一个用C语言实现的algorithm的解决scheme。 这个algorithm可以在Android的自定义混合中实现。 Drawable.setColorFilter()使用扩展ColorFilter PorterDuffColorfilter 。 在这个 SO问题中讨论的ColorFilter子类必须在使用NDK的本地代码中完成。

CMYK颜色混合解决方法

如果您有兴趣使用CMYK色彩混合作为解决方法,我已经包含了一个基本的例子,说明如何在下面完成。 在这个例子中,一个青色圆圈和一个黄色圆圈将被混合,产生一个绿色的交点。

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

在这里输入图像说明

在这里输入图像说明

用hex颜色值0x00ffff(青色)和0xffff00(黄色)。

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

configuration你的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> 

创build你的活动:

 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值)。 哪种混合模式最终可以接受取决于你要使用的一组颜色,并将需要一些实验。 另请注意,背景颜色可能会影响混合模式下的圆圈颜色。 在这个例子中,背景被设置为白色。

我已经为6个对象做了另一个例子 。

在这里输入图像说明

关键点:

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

    setBackgroundColor(Color.TRANSPARENT);

  2. 但是,onDraw方法将被重命名为onDrawEx将从覆盖视图中调用。

    public void onDrawEx(Canvas canvas){

  3. 覆盖视图将通过自定义canvas进行绘制。 在传递给对象视图之前,它将做必要的翻译。

      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(新的PorterDuffXfermode(Mode.ADD)); 添加颜色。 但是所有的对象都应该使用像0xFF000030,0xFF0000C0,0xFF003000,0xFF00C000,0xFF3003,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)); 

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

我能想到的最简单的解决scheme是简单地使用alpha通道,通过将代码或xml中的每一个设置为0.5不透明度。 然后,当它们重叠时,颜色应该互相淡入。 这样做意味着非重叠部分的颜色将会有点褪色,并且取决于背景的背景是什么也不好看。

我创build了一个示例活动与两个视图DemoDrawShapeActivity其中在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; } 

我想你可能正在寻找混合模式。 Android会让你做到这一点,只要看看这第一个链接。 Android Canvas中的复合操作

这里是所有的合成选项http://developer.android.com/reference/android/graphics/PorterDuffXfermode.html

并从Mozilla的解释https://developer.mozilla.org/en/Canvas_tutorial/Compositing