zoukankan      html  css  js  c++  java
  • Android 仿PhotoShop调色板应用(三) 主体界面绘制

    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.   
    3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    4.     android:layout_width="wrap_content"  
    5.     android:layout_height="wrap_content"  
    6.     android:orientation="vertical"  
    7.     android:paddingLeft="5dp"  
    8.     android:paddingRight="5dp" >  
    9.   
    10.     <net.margaritov.preference.colorpicker.ColorPickerView  
    11.         android:id="@+id/color_picker_view"  
    12.         android:layout_width="wrap_content"  
    13.         android:layout_height="wrap_content"  
    14.         android:layerType="software"  
    15.         android:tag="portrait" />  
    16.   
    17.     <LinearLayout  
    18.         android:id="@+id/text_hex_wrapper"  
    19.         android:layout_width="fill_parent"  
    20.         android:layout_height="wrap_content"  
    21.         android:layout_marginBottom="5dp"  
    22.         android:layout_marginLeft="6dp"  
    23.         android:layout_marginRight="6dp" >  
    24.   
    25.         <TextView  
    26.             android:layout_width="wrap_content"  
    27.             android:layout_height="wrap_content"  
    28.             android:gravity="left"  
    29.             android:text="@string/press_color_to_apply"  
    30.             android:textAppearance="?android:attr/textAppearanceSmall" />  
    31.   
    32.         <EditText  
    33.             android:id="@+id/hex_val"  
    34.             android:layout_width="0dp"  
    35.             android:layout_height="wrap_content"  
    36.             android:layout_weight="1"  
    37.             android:hint="HEX"  
    38.             android:imeOptions="actionDone"  
    39.             android:maxLength="7"  
    40.             android:singleLine="true"  
    41.             android:inputType="textCapCharacters"  
    42.             android:visibility="gone" >  
    43.         </EditText>  
    44.     </LinearLayout>  
    45.   
    46.     <LinearLayout  
    47.         android:layout_width="wrap_content"  
    48.         android:layout_height="40dp"  
    49.         android:layout_marginBottom="10dp"  
    50.         android:orientation="horizontal" >  
    51.   
    52.         <net.margaritov.preference.colorpicker.ColorPickerPanelView  
    53.             android:id="@+id/old_color_panel"  
    54.             android:layout_width="0px"  
    55.             android:layout_height="fill_parent"  
    56.             android:layout_weight="0.5" />  
    57.   
    58.         <TextView  
    59.             android:layout_width="wrap_content"  
    60.             android:layout_height="fill_parent"  
    61.             android:layout_marginLeft="10dp"  
    62.             android:layout_marginRight="10dp"  
    63.             android:gravity="center"  
    64.             android:text="→"  
    65.             android:textSize="20sp" />  
    66.   
    67.         <net.margaritov.preference.colorpicker.ColorPickerPanelView  
    68.             android:id="@+id/new_color_panel"  
    69.             android:layout_width="0px"  
    70.             android:layout_height="wrap_content"  
    71.             android:layout_weight="0.5" />  
    72.     </LinearLayout>  
    73.   
    74. </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.   
    7.         final RectF rect = mSatValRect;  
    8.   
    9.         if(BORDER_WIDTH_PX > 0){  
    10.             mBorderPaint.setColor(mBorderColor);  
    11.             canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint);  
    12.         }  
    13.         //明度线性渲染器  
    14.         if (mValShader == null) {  
    15.             mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,  
    16.                     0xffffffff, 0xff000000, TileMode.CLAMP);  
    17.         }  
    18.         //HSV转化为RGB  
    19.         int rgb = Color.HSVToColor(new float[]{mHue,1f,1f});  
    20.         //饱和线性渲染器  
    21.         mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,  
    22.                 0xffffffff, rgb, TileMode.CLAMP);  
    23.         //组合渲染 = 明度线性渲染器 + 饱和线性渲染器  
    24.         ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);  
    25.         mSatValPaint.setShader(mShader);  
    26.   
    27.         canvas.drawRect(rect, mSatValPaint);  
    28.         //初始化选择圆块的位置  
    29.         Point p = satValToPoint(mSat, mVal);  
    30.         //绘制黑色内圆  
    31.         mSatValTrackerPaint.setColor(0xff000000);  
    32.         canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint);  
    33.         //绘制外圆  
    34.         mSatValTrackerPaint.setColor(0xffdddddd);  
    35.         canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint);  
    36.   
    37.     }  


    2.Hue Area 色相选择区域

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

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


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

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

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

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

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


    3. Alpha Area 透明度选择区域

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

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

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

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

    4. ColorPickerPanelView

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

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

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


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

  • 相关阅读:
    重建二叉树
    从尾到头打印链表
    合并两个数组
    替换空格
    二维数组中的查找
    机器学习中的 precision、recall、accuracy、F1 Score
    rand、randi和randn的区别?
    使用自己的数据集训练和测试"caffenet"
    caffe环境的搭建(Ubuntu14.04 64bit,无CUDA,caffe在CPU下运行)
    Java 并发工具包 java.util.concurrent 用户指南
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5571867.html
Copyright © 2011-2022 走看看