版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 仿PhotoShop调色板应用(三) 主体界面绘制

   关于PhotoShop调色板应用的实现我总结了两个最核心的部分:

  1. 主体界面不同区域的绘制

  2. 颜色选择的生成与交互

这里我讲述一下第一要点,也就是ColorPickerDialog对主体界面的绘制.

首先还是看一下ColorPickerDialog整体显示的效果(见图1)

    图1

对应着效果图我画了一张界面结构分析图,相信看了之后会对该界面的组成很快能够掌握:(见图2)

  图2

一. 界面组成

可以看到整个显示的部分即为ColorPickerDialog. 这个Dialog根据组件的构成及功能实现上可以分为两大部分:

  1. 红色边框区域 ColorPickerView绘制而成. 主要作为颜色区域的选择,此区域又划分为三个部分:

   (1)  Saturation Area 饱和度选择区域

      (2)  Hue Area 色相选择区域

(3)  Alpha Area 透明度选择区域  绘制此区域借助了上一篇讲到的AlphaPatternDrawable类

2. 蓝色边框区域 由ColorPickerPanelView绘制. 左边的部分作为初始颜色显示 右边的部分做颜色选择的实时显示区域,点击后可将颜色设置为默认值

该Dialog的布局文件dialog_color_picker.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:orientation="vertical"
  6. android:paddingLeft="5dp"
  7. android:paddingRight="5dp" >
  8. <net.margaritov.preference.colorpicker.ColorPickerView
  9. android:id="@+id/color_picker_view"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:layerType="software"
  13. android:tag="portrait" />
  14. <LinearLayout
  15. android:id="@+id/text_hex_wrapper"
  16. android:layout_width="fill_parent"
  17. android:layout_height="wrap_content"
  18. android:layout_marginBottom="5dp"
  19. android:layout_marginLeft="6dp"
  20. android:layout_marginRight="6dp" >
  21. <TextView
  22. android:layout_width="wrap_content"
  23. android:layout_height="wrap_content"
  24. android:gravity="left"
  25. android:text="@string/press_color_to_apply"
  26. android:textAppearance="?android:attr/textAppearanceSmall" />
  27. <EditText
  28. android:id="@+id/hex_val"
  29. android:layout_width="0dp"
  30. android:layout_height="wrap_content"
  31. android:layout_weight="1"
  32. android:hint="HEX"
  33. android:imeOptions="actionDone"
  34. android:maxLength="7"
  35. android:singleLine="true"
  36. android:inputType="textCapCharacters"
  37. android:visibility="gone" >
  38. </EditText>
  39. </LinearLayout>
  40. <LinearLayout
  41. android:layout_width="wrap_content"
  42. android:layout_height="40dp"
  43. android:layout_marginBottom="10dp"
  44. android:orientation="horizontal" >
  45. <net.margaritov.preference.colorpicker.ColorPickerPanelView
  46. android:id="@+id/old_color_panel"
  47. android:layout_width="0px"
  48. android:layout_height="fill_parent"
  49. android:layout_weight="0.5" />
  50. <TextView
  51. android:layout_width="wrap_content"
  52. android:layout_height="fill_parent"
  53. android:layout_marginLeft="10dp"
  54. android:layout_marginRight="10dp"
  55. android:gravity="center"
  56. android:text="→"
  57. android:textSize="20sp" />
  58. <net.margaritov.preference.colorpicker.ColorPickerPanelView
  59. android:id="@+id/new_color_panel"
  60. android:layout_width="0px"
  61. android:layout_height="wrap_content"
  62. android:layout_weight="0.5" />
  63. </LinearLayout>
  64. </LinearLayout>

二. 不同区域的绘制实现:

1.     Saturation Area 饱和度选择区域

这里用到了组合渲染(ComposeShader)的方式.

(1)使用了两个线性渲染器:一个作为亮度的显示渲染,一个作为饱和度的显示渲染,    因为我们可以看到颜色渐变和亮度渐变的综合显示效果

此区域完成了HSV(也叫HSB)色彩空间之Saturation(饱和度)value(色调)/brightness(明度)的综合显示

(2) 选择圆环绘制:  分为了内外两个圆环分别绘制. 黑色内圆及灰色外圆

具体实现请看以下代码

  1. /**
  2. * 绘制饱和度选择区域
  3. * @param canvas
  4. */
  5. private void drawSatValPanel(Canvas canvas){
  6. final RectF rect = mSatValRect;
  7. if(BORDER_WIDTH_PX > 0){
  8. mBorderPaint.setColor(mBorderColor);
  9. canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint);
  10. }
  11. //明度线性渲染器
  12. if (mValShader == null) {
  13. mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,
  14. 0xffffffff, 0xff000000, TileMode.CLAMP);
  15. }
  16. //HSV转化为RGB
  17. int rgb = Color.HSVToColor(new float[]{mHue,1f,1f});
  18. //饱和线性渲染器
  19. mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
  20. 0xffffffff, rgb, TileMode.CLAMP);
  21. //组合渲染 = 明度线性渲染器 + 饱和线性渲染器
  22. ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);
  23. mSatValPaint.setShader(mShader);
  24. canvas.drawRect(rect, mSatValPaint);
  25. //初始化选择圆块的位置
  26. Point p = satValToPoint(mSat, mVal);
  27. //绘制黑色内圆
  28. mSatValTrackerPaint.setColor(0xff000000);
  29. canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint);
  30. //绘制外圆
  31. mSatValTrackerPaint.setColor(0xffdddddd);
  32. canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint);
  33. }

2.Hue Area 色相选择区域

(1) 颜色渲染部分仍为竖直方向的线性渐变.这里可以看一下对应颜色数组的生成:

  1. private int[] buildHueColorArray(){
  2. int[] hue = new int[361];
  3. int count = 0;
  4. for(int i = hue.length -1; i >= 0; i--, count++){
  5. hue[count] = Color.HSVToColor(new float[]{i, 1f, 1f});
  6. }
  7. return hue;
  8. }

这里使用了一个大小为361的int数组, 根据当前位置生成不同的 hsv颜色数组

通过Color.HSVToColor,将HSV转换为ARGB的形式,因为在线性渐变渲染中,我们不能直接使用HSV色彩,而是需要使用ARGB制式的颜色.

因此我们看到了一个数值方向的一个多彩变换效果

(2) 绘制矩形颜色选择条区域

  1. /**
  2. * 绘制右侧色相选择区域
  3. * @param canvas
  4. */
  5. private void drawHuePanel(Canvas canvas){
  6. final RectF rect = mHueRect;
  7. if(BORDER_WIDTH_PX > 0){
  8. mBorderPaint.setColor(mBorderColor);
  9. canvas.drawRect(rect.left - BORDER_WIDTH_PX,
  10. rect.top - BORDER_WIDTH_PX,
  11. rect.right + BORDER_WIDTH_PX,
  12. rect.bottom + BORDER_WIDTH_PX,
  13. mBorderPaint);
  14. }
  15. //初始化色相线性渲染器
  16. if (mHueShader == null) {
  17. mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, buildHueColorArray(), null, TileMode.CLAMP);
  18. mHuePaint.setShader(mHueShader);
  19. }
  20. canvas.drawRect(rect, mHuePaint);
  21. float rectHeight = 4 * mDensity / 2;
  22. //初始化色相选择器选择条位置
  23. Point p = hueToPoint(mHue);
  24. RectF r = new RectF();
  25. r.left = rect.left - RECTANGLE_TRACKER_OFFSET;
  26. r.right = rect.right + RECTANGLE_TRACKER_OFFSET;
  27. r.top = p.y - rectHeight;
  28. r.bottom = p.y + rectHeight;
  29. //绘制选择条
  30. canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
  31. }


3. Alpha Area 透明度选择区域

这里主要借助于AlphaPatternDrawable进行绘制,见上一篇博客:

Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable

具体请见注释,渲染部分和Hue Area类似

  1. /**
  2. * 绘制底部透明度选择区域
  3. * @param canvas
  4. */
  5. private void drawAlphaPanel(Canvas canvas){
  6. if(!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return;
  7. final RectF rect = mAlphaRect;
  8. if(BORDER_WIDTH_PX > 0){
  9. mBorderPaint.setColor(mBorderColor);
  10. canvas.drawRect(rect.left - BORDER_WIDTH_PX,
  11. rect.top - BORDER_WIDTH_PX,
  12. rect.right + BORDER_WIDTH_PX,
  13. rect.bottom + BORDER_WIDTH_PX,
  14. mBorderPaint);
  15. }
  16. mAlphaPattern.draw(canvas);
  17. float[] hsv = new float[]{mHue,mSat,mVal};//hsv数组
  18. int color = Color.HSVToColor(hsv);
  19. int acolor = Color.HSVToColor(0, hsv);
  20. //初始化透明度线性渲染器
  21. mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
  22. color, acolor, TileMode.CLAMP);
  23. mAlphaPaint.setShader(mAlphaShader);
  24. canvas.drawRect(rect, mAlphaPaint);
  25. if(mAlphaSliderText != null && mAlphaSliderText!= ""){
  26. canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, mAlphaTextPaint);
  27. }
  28. float rectWidth = 4 * mDensity / 2;
  29. //初始化透明度选择器选择条位置
  30. Point p = alphaToPoint(mAlpha);
  31. RectF r = new RectF();
  32. r.left = p.x - rectWidth;
  33. r.right = p.x + rectWidth;
  34. r.top = rect.top - RECTANGLE_TRACKER_OFFSET;
  35. r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET;
  36. canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
  37. }

4. ColorPickerPanelView

由于此区域可做最终颜色的显示,所以也借助了AlphaPatternDrawable的实现

此矩形区域绘制相对比较简单:

  1. final RectF rect = mColorRect;
  2. if(BORDER_WIDTH_PX > 0){
  3. mBorderPaint.setColor(mBorderColor);
  4. canvas.drawRect(mDrawingRect, mBorderPaint);
  5. }
  6. if(mAlphaPattern != null){
  7. mAlphaPattern.draw(canvas);
  8. }
  9. mColorPaint.setColor(mColor);
  10. canvas.drawRect(rect, mColorPaint);

至此,ColorPickerDialog主体面板绘制部分已讲述完毕.下面我会讲述另一大核心部分:颜色选择生成的交互.
如果对颜色渲染方面还是不太清楚的话,可以参照我之前写的颜色渲染系列,关于原理和具体API的讲解.

Android 仿PhotoShop调色板应用(三) 主体界面绘制的更多相关文章

  1. Android 仿PhotoShop调色板应用(四) 不同区域颜色选择的颜色生成响应

    版权声明:本文为博主原创文章,未经博主允许不得转载.  Android 仿PhotoShop调色板应用(四) 不同区域颜色选择的颜色生成响应  上一篇讲过了主体界面的绘制,这里讲解调色板应用中的另外一 ...

  2. Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable 这里讲一下如何实现PS调色板中的透明度 ...

  3. Android 仿PhotoShop调色板应用(一)概述

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在前面的系列我已经将Android中颜色渲染的原理及使用做了一个整体上概述. 现在开始根据一个比较复杂的实现进行具体的分析,这就是PhotoSho ...

  4. Android图形显示系统——上层显示1:界面绘制大纲

    Android显示之应用界面绘制 越到上层,跟业务关联越直接.代码就越繁杂.Android上层显示的代码正是如此.此外,java语言本身繁复的特点(比C语言多了满屏的try-catch,比C++少了析 ...

  5. Android 仿Win8的metro的UI界面(上)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23441455 昨晚没事手机下载了一些APP,发现现在仿win8的主界面越来越多, ...

  6. Android 仿百度医生的智能分诊界面

    http://blog.csdn.net/jiang89125/article/details/49622853

  7. Android仿人人客户端(v5.7.1)——个人主页(三)

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/9405089 声明:仿人人项目,所用所有图片资源都来源于其它Android移动应用,编 ...

  8. 安卓开发笔记(三十三):Android仿写微信发现

    首先我们来看看仿写之后的效果: 看到是这个界面我们首先应该思考这些按钮是怎么做出来的?有了一个整体的思路之后才知道该怎么办.最开始我想的就直接利用button控件上面直接加上png的图片就可以形成一个 ...

  9. android高仿抖音、点餐界面、天气项目、自定义view指示、爬取美女图片等源码

    Android精选源码 一个爬取美女图片的app Android高仿抖音 android一个可以上拉下滑的Ui效果 android用shape方式实现样式源码 一款Android上的新浪微博第三方轻量 ...

随机推荐

  1. window.frameElement属性

    比如有一个iframe的src是xxx.htm frameElement的作用就是在xxx.htm中获得这个引用它的iframe objet 这样你就可以在xxx.htm改变iframe的大小,或是边 ...

  2. Android 下拉刷新控件Android-PullToRefresh

    需要用到一个开源库 Android-PullToRefresh https://github.com/chrisbanes/Android-PullToRefresh ---------------- ...

  3. Python自动化运维之1、Python入门

    Python简介 python是吉多·范罗苏姆发明的一种面向对象的脚本语言,可能有些人不知道面向对象和脚本具体是什么意思,但是对于一个初学者来说,现在并不需要明白.大家都知道,当下全栈工程师的概念很火 ...

  4. ASP.NET MVC轻教程 Step By Step 10——模型验证

    在使用表单获取用户输入的数据时,我们必须对数据进行有效性验证,因为来自网络的信息都是不可信的.同时也要给用户即时的反馈,避免让用户感到困惑.这就涉及到数据验证的范畴. 数据验证最直接的做法是在服务器端 ...

  5. 手动实现 NSTabViewController 的 Rect Transition 及 Propagate Title-b

    不知为何 我在 OS X 10.11.5 及 Xcode 7.3 的 Storyboard 中设置 Tab View Controller 的 Transition 属性时,Tab View Cont ...

  6. js中的字符串

    JS里并没有标准的多行字符串的表示方法,但是在用模板的时候,为了保证模板的可阅读性,我们又不可避免的使用多行字符串,所以出现了各种搞法,这里以一段jade的模板作为示例,简单总结和对比一下. 字符串相 ...

  7. SQL Server日期函数之获得一个月中的天数

    SQL Server日期函数之获得一个月中的天数在实际中的应用比例还是占为多数的,如果你对这一技术,心存好奇的话,以下的文章将会揭开它的神秘面纱,望会在以后的学习或是工作中带来很大的帮助. 获得一个月 ...

  8. Uva_11021 Tribles

    题目链接 题意: 现在有k只麻球, 每只麻球只能存活一天, 第二天就会死去, 死去之前可能生下x只小麻球(x = 0,1,2,...,n  1), 概率分别为P[0], P[1], ... , P[n ...

  9. CTSC模拟题 树上的路径

    Description 给定一棵\(N\)个结点的树,结点用正整数\(1 \dots N\)编号,每条边有一个正整数权值.用\(d(a, b)\)表示从结点\(a\)到结点\(b\)路径上经过边的权值 ...

  10. [BZOJ 1218] [HNOI2003] 激光炸弹 【n logn 做法 - 扫描线 + 线段树】

    题目链接:BZOJ - 1218 题目分析 可以覆盖一个边长为 R 的正方形,但是不能包括边界,所以等价于一个边长为 R - 1 的正方形. 坐标范围 <= 5000 ,直接 n^2 的二维前缀 ...