在Api Demo里面有一个叫ColorPickerDialog的对话框,该对话框扩展了Dialog 的功能,使其具备颜色选择器的功能。具体可以参考Api Demo源代码,路径为:android-sdk-windows\samples\android-7\ApiDemos\src\com\example\android\apis\graphics\ColorPickerDialog.java
本功能是基于上述的颜色选择器对话框进行扩展,模仿PreferceActivity 组件的实现方式,新建一个名为ColorPickerPreference 的类使其继承自DialogPreference 并实现其内部功能菜单,如图:
在Api Demo里面的颜色选择器是不具备有黑色和白色的选择的,这里我们虽然使用api Demo 里面的颜色选择器但其内部我们稍稍改造了一下。使其支持黑色和白色的选择,如上图中间的一条颜色条,头部和尾部分别代表黑色和白色。
为了显示的友好性,如果用户选择了颜色应该应该会有一个内容窗口或者一个文本对用户的选择做出相应的预览效果,。我们这里使用了一个TextView 做为颜色的预览效果,我们知道,Preference 的summary 只支持字符串的操作,类似下面的图:
如上图,只支持类型类型为CharSequence和字符所在的资源ID位置,那么我们这里如何使其支持颜色的显示和动态更换颜色呢?
这一切都在神奇的回调函数,onCreateView 里面这个方法先于 onBindView 执行,在里面初始化视图并且返回视图。具体处理见下面代码:
 
    @Override
    
protected  View onCreateView(ViewGroup parent) {
        
//  TODO Auto-generated method stub

        View view 
=  LayoutInflater.from(getContext()).inflate(
                R.layout.preference, 
null );

        TextView title 
=  (TextView) view.findViewById(R.id.title);
        title.setText(getTitle());

        summary 
=  (TextView) view.findViewById(R.id.summary);
        summary.setText(getSummary());
        SharedPreferences prefs 
=  getPreferenceManager().getSharedPreferences();
        mInitialColor 
=  prefs.getInt(getKey(), Color.LTGRAY);
        summary.setTextColor(mInitialColor); 
        
return  view;
    }
 
 
上面代码,我们通过LayoutInflater 函数引入一个外部的布局文件,然后设置其title 和summary 并初始其颜色,通过SharedPreferences 类调用保存后的颜色值,布局文件如下:
 
xml version="1.0" encoding="UTF-8" ?>
< LinearLayout  android:id ="@+id/LinearLayout01"
    android:layout_width
="fill_parent"  android:layout_height ="fill_parent"
    xmlns:android
="http://schemas.android.com/apk/res/android" >


    
< RelativeLayout  android:layout_width ="fill_parent"
        android:gravity
="center"  android:layout_height ="fill_parent" >
        
< TextView  android:id ="@+id/title"  android:layout_width ="wrap_content"
            android:layout_marginLeft
="15dp"  android:textAppearance ="?android:attr/textAppearanceLarge"
            android:layout_height
="wrap_content" > TextView >
        
< ImageView  android:src ="@drawable/ic_dialog_menu_generic"
            android:layout_marginRight
="15dp"  android:layout_alignParentRight ="true"
            android:layout_width
="wrap_content"  android:layout_height ="wrap_content" > ImageView >
        
< TextView  android:id ="@+id/summary"  android:layout_below ="@id/title"
            android:layout_marginLeft
="15dp"  android:layout_width ="wrap_content"
            android:layout_height
="wrap_content" > TextView >

    
RelativeLayout >
LinearLayout >
 
 
 
实始化对话框的回调函数里面我们为其添加一个ColorPickerDialog 本身的颜色改变的事件监听并为其初始化颜色值,代码如下:
 
@Override
    
protected  void  onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);

        OnColorChangedListener l 
=  new  OnColorChangedListener() {
            
public  void  colorChanged( int  color) {
                mCurrentColor 
=  color;
                onDialogClosed(
true );
                getDialog().dismiss();
            }
        }; 

        LinearLayout layout 
=  new  LinearLayout(getContext());
        layout.setPadding(
20 20 20 20 );
        layout.setOrientation(LinearLayout.VERTICAL);
        mCPView 
=  new  ColorPickerView(getContext(), l, mInitialColor);

        LinearLayout.LayoutParams params1 
=  new  LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params1.gravity 
=  Gravity.CENTER;
        mCPView.setLayoutParams(params1);
        layout.addView(
this .mCPView);
        layout.setId(android.R.id.widget_frame);
        builder.setView(layout);
    }
 
 
当对话框关闭时,即选择完颜色后,我们就要马上回去更新文本的颜色和将颜色值保存到键值里面,代码如下:
 
    @Override
    
protected  void  onDialogClosed(boolean positiveResult) {
        
if  (positiveResult) {
            mCurrentColor 
=  mCPView.getColor();
            summary.setTextColor(mCurrentColor);
            SharedPreferences.Editor editor 
=  getEditor();
            editor.putInt(getKey(), mCurrentColor);
            editor.commit();
            callChangeListener(
new  Integer(mCurrentColor));
        }
    }
 
通过重写,onDialogClosed 回调函数,到这一步整个的封装就己结束,在XML可以通过如下使用:
 
< com.terry.util.ColorPickerPreference
            
android:key ="colorpiker"  android:persistent ="true"  android:summary ="@string/app_name"
            android:dialogTitle
="@string/str_fontscolor"  android:title ="@string/str_fontscolor"  />
 
 
Tip:自己封装控件不论是自定义控件也好,preference 也好在XML里面都是无法智能提示的,只要自己把握好输入的属性准确无误就行。
完整代码如下:
 
package com.terry.util;

import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.terry.eBook.R;

public  class  ColorPickerPreference extends DialogPreference {
    
private  int  mInitialColor;
    
private  int  mCurrentColor;
    
private  ColorPickerView mCPView;
    
private  TextView summary;

    
private  static  class  ColorPickerView extends View {
        
private  Paint mPaint;
        
private  Paint mCenterPaint;
        
private  Paint mHSVPaint;
        
private  final  int [] mColors;
        
private  int [] mHSVColors;
        
private  boolean mRedrawHSV;
        
private  OnColorChangedListener mListener;

        ColorPickerView(Context c, OnColorChangedListener l, 
int  color) {
            super(c);
            mListener 
=  l;
            mColors 
=  new  int [] {  0xFFFF0000 0xFFFF00FF 0xFF0000FF ,
                    
0xFF00FFFF 0xFF00FF00 0xFFFFFF00 0xFFFF0000  };
            Shader s 
=  new  SweepGradient( 0 0 , mColors,  null );

            mPaint 
=  new  Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setShader(s);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(
55 );

            mCenterPaint 
=  new  Paint(Paint.ANTI_ALIAS_FLAG);
            mCenterPaint.setColor(color);
            mCenterPaint.setStrokeWidth(
5 );

            mHSVColors 
=  new  int [] {  0xFF000000 , color,  0xFFFFFFFF  };

            mHSVPaint 
=  new  Paint(Paint.ANTI_ALIAS_FLAG);
            mHSVPaint.setStrokeWidth(
10 );

            mRedrawHSV 
=  true ;

        }

        
private  boolean mTrackingCenter;
        
private  boolean mHighlightCenter;

        
public  int  getColor() {
            
return  mCenterPaint.getColor();
        }

        @Override
        
protected  void  onDraw(Canvas canvas) {
            
float  r  =  CENTER_X  -  mPaint.getStrokeWidth()  *  0.5f ;

            canvas.translate(CENTER_X, CENTER_X);
            
int  c  =  mCenterPaint.getColor();

            
if  (mRedrawHSV) {
                mHSVColors[
1 =  c;
                mHSVPaint.setShader(
new  LinearGradient( - 100 0 100 0 ,
                        mHSVColors, 
null , Shader.TileMode.CLAMP));
            }

            canvas.drawOval(
new  RectF( - r,  - r, r, r), mPaint);
            canvas.drawCircle(
0 0 , CENTER_RADIUS, mCenterPaint);
            canvas.drawRect(
new  RectF( - 100 130 100 110 ), mHSVPaint);

            
if  (mTrackingCenter) {
                mCenterPaint.setStyle(Paint.Style.STROKE);

                
if  (mHighlightCenter) {
                    mCenterPaint.setAlpha(
0xFF );
                } 
else  {
                    mCenterPaint.setAlpha(
0x80 );
                }
                canvas.drawCircle(
0 0 , CENTER_RADIUS
                        
+  mCenterPaint.getStrokeWidth(), mCenterPaint);

                mCenterPaint.setStyle(Paint.Style.FILL);
                mCenterPaint.setColor(c);
            }

            mRedrawHSV 
=  true ;
        }

        @Override
        
protected  void  onMeasure( int  widthMeasureSpec,  int  heightMeasureSpec) {
            setMeasuredDimension(CENTER_X 
*  2 , (CENTER_Y  +  25 *  2 );
        }

        
private  static  final  int  CENTER_X  =  100 ;
        
private  static  final  int  CENTER_Y  =  100 ;
        
private  static  final  int  CENTER_RADIUS  =  30 ;

        
private  int  ave( int  s,  int  d,  float  p) {
            
return  s  +  java.lang.Math.round(p  *  (d  -  s));
        }

        
private  int  interpColor( int  colors[],  float  unit) {
            
if  (unit  <=  0 ) {
                
return  colors[ 0 ];
            }
            
if  (unit  >=  1 ) {
                
return  colors[colors.length  -  1 ];
            }

            
float  p  =  unit  *  (colors.length  -  1 );
            
int  i  =  ( int ) p;
            p 
-=  i;

            
//  now p is just the fractional part [0...1) and i is the index
             int  c0  =  colors[i];
            
int  c1  =  colors[i  +  1 ];
            
int  a  =  ave(Color.alpha(c0), Color.alpha(c1), p);
            
int  r  =  ave(Color.red(c0), Color.red(c1), p);
            
int  g  =  ave(Color.green(c0), Color.green(c1), p);
            
int  b  =  ave(Color.blue(c0), Color.blue(c1), p);

            
return  Color.argb(a, r, g, b);
        }

        
private  static  final  float  PI  =  3.1415926f ;

        @Override
        
public  boolean onTouchEvent(MotionEvent  event ) {
            
float  x  =  event .getX()  -  CENTER_X;
            
float  y  =  event .getY()  -  CENTER_Y;
            boolean inCenter 
=  java.lang.Math.sqrt(x  *  x  +  y  *  y)  <=  CENTER_RADIUS;

            
switch  ( event .getAction()) {
            
case  MotionEvent.ACTION_DOWN:
                mTrackingCenter 
=  inCenter;
                
if  (inCenter) {
                    mHighlightCenter 
=  true ;
                    invalidate();
                    
break ;
                }
            
case  MotionEvent.ACTION_MOVE:
                
if  (mTrackingCenter) {
                    
if  (mHighlightCenter  !=  inCenter) {
                        mHighlightCenter 
=  inCenter;
                        invalidate();
                    }
                } 
else  if  ((x  >=  - 100  &  x  <=  100 &&  (y  <=  130  &&  y  >=  110 ))  //  see
                
//  if
                
//  we're
                
//  in
                
//  the
                
//  hsv
                
//  slider
                {
                    
int  a, r, g, b, c0, c1;
                    
float  p;

                    
//  set the center paint to this color
                     if  (x  <  0 ) {
                        c0 
=  mHSVColors[ 0 ];
                        c1 
=  mHSVColors[ 1 ];
                        p 
=  (x  +  100 /  100 ;
                    } 
else  {
                        c0 
=  mHSVColors[ 1 ];
                        c1 
=  mHSVColors[ 2 ];
                        p 
=  x  /  100 ;
                    }

                    a 
=  ave(Color.alpha(c0), Color.alpha(c1), p);
                    r 
=  ave(Color.red(c0), Color.red(c1), p);
                    g 
=  ave(Color.green(c0), Color.green(c1), p);
                    b 
=  ave(Color.blue(c0), Color.blue(c1), p);

                    mCenterPaint.setColor(Color.argb(a, r, g, b));

                    mRedrawHSV 
=  false ;
                    invalidate();
                } 
else  {
                    
float  angle  =  ( float ) java.lang.Math.atan2(y, x);
                    
//  need to turn angle [-PI ... PI] into unit [0....1]
                     float  unit  =  angle  /  ( 2  *  PI);
                    
if  (unit  <  0 ) {
                        unit 
+=  1 ;
                    }
                    mCenterPaint.setColor(interpColor(mColors, unit));
                    invalidate();
                }
                
break ;
            
case  MotionEvent.ACTION_UP:
                
if  (mTrackingCenter) {
                    
if  (inCenter) {
                        mListener.colorChanged(mCenterPaint.getColor());
                    }
                    mTrackingCenter 
=  false //  so we draw w/o halo
                    invalidate();
                }
                
break ;
            }
            
return  true ;
        }
    }

    
public  interface  OnColorChangedListener {
        
void  colorChanged( int  color);
    }

    
public  ColorPickerPreference(Context contex) {
        
this (contex,  null );
    }

    
public  ColorPickerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    
public  ColorPickerPreference(Context context, AttributeSet attrs,
            
int  defStyle) {
        super(context, attrs, defStyle);

    }

    @Override
    
protected  void  onDialogClosed(boolean positiveResult) {
        
if  (positiveResult) {
            mCurrentColor 
=  mCPView.getColor();
            summary.setTextColor(mCurrentColor);
            SharedPreferences.Editor editor 
=  getEditor();
            editor.putInt(getKey(), mCurrentColor);
            editor.commit();
            callChangeListener(
new  Integer(mCurrentColor));
        }
    }

    @Override
    
protected  View onCreateView(ViewGroup parent) {
        
//  TODO Auto-generated method stub

        View view 
=  LayoutInflater.from(getContext()).inflate(
                R.layout.preference, 
null );

        TextView title 
=  (TextView) view.findViewById(R.id.title);
        title.setText(getTitle());

        summary 
=  (TextView) view.findViewById(R.id.summary);
        summary.setText(getSummary());
        SharedPreferences prefs 
=  getPreferenceManager().getSharedPreferences();
        mInitialColor 
=  prefs.getInt(getKey(), Color.LTGRAY);
        summary.setTextColor(mInitialColor); 
        
return  view;
    }

    @Override
    
protected  void  onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);

        OnColorChangedListener l 
=  new  OnColorChangedListener() {
            
public  void  colorChanged( int  color) {
                mCurrentColor 
=  color;
                onDialogClosed(
true );
                getDialog().dismiss();
            }
        }; 

        LinearLayout layout 
=  new  LinearLayout(getContext());
        layout.setPadding(
20 20 20 20 );
        layout.setOrientation(LinearLayout.VERTICAL);
        mCPView 
=  new  ColorPickerView(getContext(), l, mInitialColor);

        LinearLayout.LayoutParams params1 
=  new  LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params1.gravity 
=  Gravity.CENTER;
        mCPView.setLayoutParams(params1);
        layout.addView(
this .mCPView);
        layout.setId(android.R.id.widget_frame);
        builder.setView(layout);
    }
}
完。