• 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:

    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingLeft="5dp"
        android:paddingRight="5dp" >
    
        <net.margaritov.preference.colorpicker.ColorPickerView
            android:id="@+id/color_picker_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layerType="software"
            android:tag="portrait" />
    
        <LinearLayout
            android:id="@+id/text_hex_wrapper"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="6dp"
            android:layout_marginRight="6dp" >
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="left"
                android:text="@string/press_color_to_apply"
                android:textAppearance="?android:attr/textAppearanceSmall" />
    
            <EditText
                android:id="@+id/hex_val"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="HEX"
                android:imeOptions="actionDone"
                android:maxLength="7"
                android:singleLine="true"
                android:inputType="textCapCharacters"
                android:visibility="gone" >
            </EditText>
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginBottom="10dp"
            android:orientation="horizontal" >
    
            <net.margaritov.preference.colorpicker.ColorPickerPanelView
                android:id="@+id/old_color_panel"
                android:layout_width="0px"
                android:layout_height="fill_parent"
                android:layout_weight="0.5" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:gravity="center"
                android:text="→"
                android:textSize="20sp" />
    
            <net.margaritov.preference.colorpicker.ColorPickerPanelView
                android:id="@+id/new_color_panel"
                android:layout_width="0px"
                android:layout_height="wrap_content"
                android:layout_weight="0.5" />
        </LinearLayout>
    
    </LinearLayout>


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

      1.     Saturation Area 饱和度选择区域

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

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

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

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

          具体实现请看以下代码

    /**
    	 * 绘制饱和度选择区域
    	 * @param canvas
    	 */
    	private void drawSatValPanel(Canvas canvas){
    
    		final RectF	rect = mSatValRect;
    
    		if(BORDER_WIDTH_PX > 0){
    			mBorderPaint.setColor(mBorderColor);
    			canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint);
    		}
    		//明度线性渲染器
    		if (mValShader == null) {
    			mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,
    					0xffffffff, 0xff000000, TileMode.CLAMP);
    		}
    		//HSV转化为RGB
    		int rgb = Color.HSVToColor(new float[]{mHue,1f,1f});
    		//饱和线性渲染器
    		mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
    				0xffffffff, rgb, TileMode.CLAMP);
    		//组合渲染 = 明度线性渲染器 + 饱和线性渲染器
    		ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);
    		mSatValPaint.setShader(mShader);
    
    		canvas.drawRect(rect, mSatValPaint);
    		//初始化选择圆块的位置
    		Point p = satValToPoint(mSat, mVal);
    		//绘制黑色内圆
    		mSatValTrackerPaint.setColor(0xff000000);
    		canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint);
    		//绘制外圆
    		mSatValTrackerPaint.setColor(0xffdddddd);
    		canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint);
    
    	}


    2.Hue Area 色相选择区域

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

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


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

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

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

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

    /**
    	 * 绘制右侧色相选择区域
    	 * @param canvas
    	 */
    	private void drawHuePanel(Canvas canvas){
    
    		final RectF rect = mHueRect;
    
    		if(BORDER_WIDTH_PX > 0){
    			mBorderPaint.setColor(mBorderColor);
    			canvas.drawRect(rect.left - BORDER_WIDTH_PX,
    					rect.top - BORDER_WIDTH_PX,
    					rect.right + BORDER_WIDTH_PX,
    					rect.bottom + BORDER_WIDTH_PX,
    					mBorderPaint);
    		}
    		//初始化色相线性渲染器
    		if (mHueShader == null) {
    			mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, buildHueColorArray(), null, TileMode.CLAMP);
    			mHuePaint.setShader(mHueShader);
    		}
    
    		canvas.drawRect(rect, mHuePaint);
    
    		float rectHeight = 4 * mDensity / 2;
    		//初始化色相选择器选择条位置
    		Point p = hueToPoint(mHue);
    
    		RectF r = new RectF();
    		r.left = rect.left - RECTANGLE_TRACKER_OFFSET;
    		r.right = rect.right + RECTANGLE_TRACKER_OFFSET;
    		r.top = p.y - rectHeight;
    		r.bottom = p.y + rectHeight;
    
    		//绘制选择条
    		canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
    
    	}


    3. Alpha Area 透明度选择区域

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

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

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

    /**
    	 * 绘制底部透明度选择区域
    	 * @param canvas
    	 */
    	private void drawAlphaPanel(Canvas canvas){
    
    		if(!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return;
    
    		final RectF rect = mAlphaRect;
    
    		if(BORDER_WIDTH_PX > 0){
    			mBorderPaint.setColor(mBorderColor);
    			canvas.drawRect(rect.left - BORDER_WIDTH_PX,
    					rect.top - BORDER_WIDTH_PX,
    					rect.right + BORDER_WIDTH_PX,
    					rect.bottom + BORDER_WIDTH_PX,
    					mBorderPaint);
    		}
    
    		
    		mAlphaPattern.draw(canvas);
    		
    		float[] hsv = new float[]{mHue,mSat,mVal};//hsv数组
    		int color = Color.HSVToColor(hsv);
    		int acolor = Color.HSVToColor(0, hsv);
    		//初始化透明度线性渲染器
    		mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
    				color, acolor, TileMode.CLAMP);
    
    		
    		mAlphaPaint.setShader(mAlphaShader);
    
    		canvas.drawRect(rect, mAlphaPaint);
    
    		if(mAlphaSliderText != null && mAlphaSliderText!= ""){
    			canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, mAlphaTextPaint);
    		}
    
    		float rectWidth = 4 * mDensity / 2;
    		//初始化透明度选择器选择条位置
    		Point p = alphaToPoint(mAlpha);
    
    		RectF r = new RectF();
    		r.left = p.x - rectWidth;
    		r.right = p.x + rectWidth;
    		r.top = rect.top - RECTANGLE_TRACKER_OFFSET;
    		r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET;
    
    		canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
    
    	}

    4. ColorPickerPanelView

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

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

    	final RectF	rect = mColorRect;
    
    		if(BORDER_WIDTH_PX > 0){
    			mBorderPaint.setColor(mBorderColor);
    			canvas.drawRect(mDrawingRect, mBorderPaint);
    		}
    
    		if(mAlphaPattern != null){
    			mAlphaPattern.draw(canvas);
    		}
    
    		mColorPaint.setColor(mColor);
    
    		canvas.drawRect(rect, mColorPaint);


    至此,ColorPickerDialog主体面板绘制部分已讲述完毕.下面我会讲述另一大核心部分:颜色选择生成的交互.

    如果对颜色渲染方面还是不太清楚的话,可以参照我之前写的颜色渲染系列,关于原理和具体API的讲解.

  • 相关阅读:
    linux系统调用之系统控制
    linux系统调用之文件系统操作
    使用EF框架实现MVC的增删改查功能
    MVC+EF快速弄出一个CRUD
    Entity Framework 全面教程详解(转)
    微信小程序学习
    为Bootstrap模态对话框添加拖拽移动功能
    Razor语法大全
    EXCEL怎么打20位以上的数字?
    C# SQLite 数据库操作学习
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3320077.html
Copyright © 2020-2023  润新知