一个带动画效果的颜色选择对话框控件AnimatedColorPickerDialog

android4.4的日历中选择日程显示颜色的时候有一个颜色选择对话框非常漂亮,模仿他的界面我实现了一个类似的对话框,而且带有动画效果。

代码的实现可讲的地方不多,主要是采用了和AlertDialog类似的Builder方式来创建对话框,另外当每个颜色被选择的时候有个按下效果是用纯代码实现的,还有就是可以动态的判断一排可以显示多少个颜色元素。而动画效果我们是使用属性动画实现,如果要做到兼容2.3需要使用第三方库NineOldAndroids来实现属性动画。

源码如下:

package com.jcodecraeer.animatedcolorpickerdialog;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.OvershootInterpolator;
import android.widget.GridLayout;
import android.widget.GridLayout.Spec;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
public class AnimatedColorPickerDialog extends Dialog  {
    Context context;
    public static final int DIALOG_TYPE_MESSAGE = 0;
    public static final int DIALOG_TYPE_PROGRESS = 2;
    public static final int DIALOG_TYPE_ALERT = 3;
    private ColorClickListener mListener;
    private AnimatedColorPickerDialog(Context context) {
        this(context,R.style.CustomTheme);
    }
    private AnimatedColorPickerDialog(Context context, int theme){
        super(context, theme);
        this.context = context;
    }
    public interface ColorClickListener {
        void onColorClick(int color);
    }
    public void setOnColorClickListener(ColorClickListener l ){
        mListener = l;
    }
    private int getDarkerColor(int color){
        float\[\] hsv = new float\[3\];
        Color.colorToHSV(color, hsv); // convert to hsv
        // make darker
        hsv\[1\] = hsv\[1\] + 0.1f; // more saturation
        hsv\[2\] = hsv\[2\] - 0.2f; // less brightness
        int darkerColor = Color.HSVToColor(hsv);
        return  darkerColor ;
    }
    private StateListDrawable getStateDrawable(Drawable normal, Drawable pressed, Drawable focus) {
        StateListDrawable sd = new StateListDrawable();
        sd.addState(new int\[\]{android.R.attr.state_enabled, android.R.attr.state_focused}, focus);
        sd.addState(new int\[\]{android.R.attr.state_pressed, android.R.attr.state_enabled}, pressed);
        sd.addState(new int\[\]{android.R.attr.state_focused}, focus);
        sd.addState(new int\[\]{android.R.attr.state_pressed}, pressed);
        sd.addState(new int\[\]{android.R.attr.state_enabled}, normal);
        sd.addState(new int\[\]{}, normal);
        return sd;
    }
    @SuppressLint("NewApi")
    public void setnumberOfColums(int columnum, int\[\] colors) {
        TableLayout colorTable = (TableLayout)findViewById(R.id.color_group);
        int rows = colors.length % columnum == 0 ? colors.length / columnum : (colors.length / columnum) + 1;
        for(int r=0; r < rows; r++) {
            TableRow tableRow = new TableRow(context);
            for(int c = 0; c < columnum && (c + r * columnum) < colors.length ; c++) {
                final View item = new View(context);
                LayoutParams params = new LayoutParams((int)context.getResources().getDimension(R.dimen.color_circle_size), (int)context.getResources().getDimension(R.dimen.color_circle_size));
                item.setLayoutParams(params);       
                ShapeDrawable   drawableNormal = new ShapeDrawable (new OvalShape ());
                drawableNormal.getPaint().setColor(colors\[r * columnum + c\]);
                ShapeDrawable   drawablePress = new ShapeDrawable (new OvalShape ());
                drawablePress.getPaint().setColor(getDarkerColor(colors\[r * columnum + c\]));
                ShapeDrawable   drawableFocus = new ShapeDrawable (new OvalShape ());
                drawableFocus.getPaint().setColor(getDarkerColor(colors\[r * columnum + c\]));
                item.setBackground(getStateDrawable(drawableNormal, drawablePress, drawableFocus));
                item.setTag(Integer.valueOf(colors\[r * columnum + c\]));
                item.setOnClickListener(new View.OnClickListener(){
                       @Override
                       public void onClick(View view){
                           if(mListener != null){
                               Integer colorHexInObject = (Integer)item.getTag();
                               mListener.onColorClick(colorHexInObject.intValue());
                               dismiss();
                           }
                       }
                });
                LinearLayout itemContainer = new LinearLayout(context);
                TableRow.LayoutParams pa = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
                pa.setMargins(0, 0, 0, 10);
                itemContainer.setLayoutParams(pa);
                itemContainer.addView(item);
                tableRow.addView(itemContainer);
            }
            colorTable.addView(tableRow);  
         }
        //视差效果动画效果
        TextView dialogTitleText =  (TextView)findViewById(R.id.dialog_title);
        dialogTitleText.setTranslationX(-colorTable.getWidth());
        final AnimatorSet localAnimatorSet = new AnimatorSet();
        ObjectAnimator localObjectAnimator1 = ObjectAnimator.ofFloat(dialogTitleText, "translationX", -colorTable.getWidth(),0);
        localObjectAnimator1.setDuration(1200);
        localObjectAnimator1.setInterpolator(new OvershootInterpolator(1.2F));
        localAnimatorSet.play(localObjectAnimator1);
        colorTable.setTranslationX(-colorTable.getWidth());
        ObjectAnimator localObjectAnimator2 = ObjectAnimator.ofFloat(colorTable, "translationX", -colorTable.getWidth(),0);
        localObjectAnimator2.setDuration(1200);
        localObjectAnimator2.setInterpolator(new OvershootInterpolator(1.2F));
        localAnimatorSet.play(localObjectAnimator2).after(100);
        localAnimatorSet.start();
    }
    public static class Builder {
        private Context context;
        private ColorClickListener mListener;
        private int\[\] colors;
        private String title;
        public Builder(Context context) {
            this.context = context;
        }
        public Builder setOnColorClickListener(ColorClickListener l ){
            mListener = l;
            return this;
        }
        public Builder setColors(int\[\] c) {
            colors = c;
            return this;
        }
        public Builder setTitle(String t) {
            title = t;
            return this;
        }
        @SuppressLint("NewApi")
        public AnimatedColorPickerDialog create() {
            // instantiate the dialog with the custom Theme
            final AnimatedColorPickerDialog dialog = new AnimatedColorPickerDialog(context,R.style.CustomTheme);
            dialog.setContentView(R.layout.color_picker_dialog_layout);
            final TableLayout colorTable= (TableLayout)dialog.findViewById(R.id.color_group);
            colorTable.getViewTreeObserver().addOnGlobalLayoutListener(
                    new OnGlobalLayoutListener() {
                        @Override
                        public void onGlobalLayout() {
                            colorTable.getViewTreeObserver()
                                    .removeGlobalOnLayoutListener(this);
                            int leftWidth = (colorTable.getWidth() - colorTable.getPaddingLeft() * 2) % (int)context.getResources().getDimension(R.dimen.color_circle_size);
                            int tempColums = (colorTable.getWidth() - colorTable.getPaddingLeft() * 2) / (int)context.getResources().getDimension(R.dimen.color_circle_size);
                            if(leftWidth < (tempColums - 1) * 1) {
                                tempColums = tempColums -1;
                            }
                            dialog.setnumberOfColums(tempColums, colors);
                        }
            });
            dialog.setOnColorClickListener(mListener);
            TextView titleView = (TextView)dialog.findViewById(R.id.dialog_title);
            titleView.setText(title);
            View closebutton  = dialog.findViewById(R.id.close_button);
            closebutton.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view){
                    dialog.dismiss();
                }
            });
            dialog.setCanceledOnTouchOutside(true);
            return dialog;
       }
    }
}

dialog的xml代码color_picker_dialog_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content_layout"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center"
    android:gravity="center"
    android:background="#f4f4f4"
    >
   <LinearLayout
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"
       android:paddingLeft="10dip"
       android:paddingRight="10dip"
       android:paddingTop="5dip"
       android:paddingBottom="5dip"
   >
       <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
             >
            <TextView
                android:id="@+id/dialog_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="选择一个颜色主题"
                android:textColor="#333333"
                android:textStyle="bold"
                android:textSize="18dip"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
            />
            <ImageButton
                android:id="@+id/close_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:src="@drawable/ic_action_cancel"
                android:background="#00000000"
                android:layout_alignParentRight="true"
             />  
       </RelativeLayout>
    </LinearLayout>
    <TableLayout
        android:padding="10dip"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:stretchColumns="*" 
        android:id="@+id/color_group" >    
    </TableLayout>
</LinearLayout>

使用:

public void openColorDialog(View v) {
    new  AnimatedColorPickerDialog.Builder(MainActivity.this)
    .setTitle("选择一种颜色")
    .setColors(styleColors)
    .setOnColorClickListener(new AnimatedColorPickerDialog.ColorClickListener() {
        @Override
        public void onColorClick(int color) {
            colorDisplayView.setBackgroundColor(color);
        }
    }).create().show();
}

demo下载地址:https://github.com/jianghejie/AnimatedColorPickerDialog