1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.colorpicker; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.util.AttributeSet; 22import android.view.View; 23import android.view.ViewGroup; 24import android.widget.ImageView; 25import android.widget.TableLayout; 26import android.widget.TableRow; 27 28import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener; 29 30/** 31 * A color picker custom view which creates an grid of color squares. The number of squares per 32 * row (and the padding between the squares) is determined by the user. 33 */ 34public class ColorPickerPalette extends TableLayout { 35 36 public OnColorSelectedListener mOnColorSelectedListener; 37 38 private String mDescription; 39 private String mDescriptionSelected; 40 41 private int mSwatchLength; 42 private int mMarginSize; 43 private int mNumColumns; 44 45 public ColorPickerPalette(Context context, AttributeSet attrs) { 46 super(context, attrs); 47 } 48 49 public ColorPickerPalette(Context context) { 50 super(context); 51 } 52 53 /** 54 * Initialize the size, columns, and listener. Size should be a pre-defined size (SIZE_LARGE 55 * or SIZE_SMALL) from ColorPickerDialogFragment. 56 */ 57 public void init(int size, int columns, OnColorSelectedListener listener) { 58 mNumColumns = columns; 59 Resources res = getResources(); 60 if (size == ColorPickerDialog.SIZE_LARGE) { 61 mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_large); 62 mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_large); 63 } else { 64 mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_small); 65 mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_small); 66 } 67 mOnColorSelectedListener = listener; 68 69 mDescription = res.getString(R.string.color_swatch_description); 70 mDescriptionSelected = res.getString(R.string.color_swatch_description_selected); 71 } 72 73 private TableRow createTableRow() { 74 TableRow row = new TableRow(getContext()); 75 ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, 76 LayoutParams.WRAP_CONTENT); 77 row.setLayoutParams(params); 78 return row; 79 } 80 81 /** 82 * Adds swatches to table in a serpentine format. 83 */ 84 public void drawPalette(int[] colors, int selectedColor) { 85 drawPalette(colors, selectedColor, null); 86 } 87 88 /** 89 * Adds swatches to table in a serpentine format. 90 */ 91 public void drawPalette(int[] colors, int selectedColor, String[] colorContentDescriptions) { 92 if (colors == null) { 93 return; 94 } 95 96 this.removeAllViews(); 97 int tableElements = 0; 98 int rowElements = 0; 99 int rowNumber = 0; 100 101 // Fills the table with swatches based on the array of colors. 102 TableRow row = createTableRow(); 103 for (int color : colors) { 104 View colorSwatch = createColorSwatch(color, selectedColor); 105 setSwatchDescription(rowNumber, tableElements, rowElements, color == selectedColor, 106 colorSwatch, colorContentDescriptions); 107 addSwatchToRow(row, colorSwatch, rowNumber); 108 109 tableElements++; 110 rowElements++; 111 if (rowElements == mNumColumns) { 112 addView(row); 113 row = createTableRow(); 114 rowElements = 0; 115 rowNumber++; 116 } 117 } 118 119 // Create blank views to fill the row if the last row has not been filled. 120 if (rowElements > 0) { 121 while (rowElements != mNumColumns) { 122 addSwatchToRow(row, createBlankSpace(), rowNumber); 123 rowElements++; 124 } 125 addView(row); 126 } 127 } 128 129 /** 130 * Appends a swatch to the end of the row for even-numbered rows (starting with row 0), 131 * to the beginning of a row for odd-numbered rows. 132 */ 133 private static void addSwatchToRow(TableRow row, View swatch, int rowNumber) { 134 if (rowNumber % 2 == 0) { 135 row.addView(swatch); 136 } else { 137 row.addView(swatch, 0); 138 } 139 } 140 141 /** 142 * Add a content description to the specified swatch view. Because the colors get added in a 143 * snaking form, every other row will need to compensate for the fact that the colors are added 144 * in an opposite direction from their left->right/top->bottom order, which is how the system 145 * will arrange them for accessibility purposes. 146 */ 147 private void setSwatchDescription(int rowNumber, int index, int rowElements, boolean selected, 148 View swatch, String[] contentDescriptions) { 149 String description; 150 if (contentDescriptions != null && contentDescriptions.length > index) { 151 description = contentDescriptions[index]; 152 } else { 153 int accessibilityIndex; 154 if (rowNumber % 2 == 0) { 155 // We're in a regular-ordered row 156 accessibilityIndex = index + 1; 157 } else { 158 // We're in a backwards-ordered row. 159 int rowMax = ((rowNumber + 1) * mNumColumns); 160 accessibilityIndex = rowMax - rowElements; 161 } 162 163 if (selected) { 164 description = String.format(mDescriptionSelected, accessibilityIndex); 165 } else { 166 description = String.format(mDescription, accessibilityIndex); 167 } 168 } 169 swatch.setContentDescription(description); 170 } 171 172 /** 173 * Creates a blank space to fill the row. 174 */ 175 private ImageView createBlankSpace() { 176 ImageView view = new ImageView(getContext()); 177 TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength); 178 params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize); 179 view.setLayoutParams(params); 180 return view; 181 } 182 183 /** 184 * Creates a color swatch. 185 */ 186 private ColorPickerSwatch createColorSwatch(int color, int selectedColor) { 187 ColorPickerSwatch view = new ColorPickerSwatch(getContext(), color, 188 color == selectedColor, mOnColorSelectedListener); 189 TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength); 190 params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize); 191 view.setLayoutParams(params); 192 return view; 193 } 194} 195