Home | History | Annotate | Download | only in com.example.android.drawabletinting
      1 /*
      2 * Copyright 2014 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 
     17 package com.example.android.drawabletinting;
     18 
     19 import android.graphics.Color;
     20 import android.graphics.PorterDuff;
     21 import android.os.Bundle;
     22 import android.support.annotation.Nullable;
     23 import android.support.v4.app.Fragment;
     24 import android.view.LayoutInflater;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import android.widget.AdapterView;
     28 import android.widget.ArrayAdapter;
     29 import android.widget.ImageView;
     30 import android.widget.SeekBar;
     31 import android.widget.Spinner;
     32 import android.widget.SpinnerAdapter;
     33 import android.widget.TextView;
     34 
     35 import com.example.android.common.logger.Log;
     36 
     37 /**
     38  * Sample that shows tinting of Drawables programmatically and of Drawable resources in XML.
     39  * Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
     40  * A color state list is referenced as the tint color, which  defines colors for different
     41  * states of a View (for example disabled/enabled, focused, pressed or selected).
     42  * Programmatically, tinting is applied to a Drawable through its "setColorFilter" method, with
     43  * a reference to a color and a PorterDuff blend mode. The color and blend mode can be
     44  * changed from the UI.
     45  *
     46  * @see android.graphics.drawable.Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)
     47  * @see android.graphics.drawable.Drawable#setTint(android.content.res.ColorStateList, android.graphics.PorterDuff.Mode)
     48  */
     49 public class DrawableTintingFragment extends Fragment {
     50 
     51     /**
     52      * String that identifies logging output from this Fragment.
     53      */
     54     private static final String TAG = "DrawableTintingFragment";
     55 
     56     /**
     57      * Image that tinting is applied to programmatically.
     58      */
     59     private ImageView mImage;
     60 
     61     /**
     62      * Seekbar for alpha component of tinting color.
     63      */
     64     private SeekBar mAlphaBar;
     65     /**
     66      * Seekbar for red component of tinting color.
     67      */
     68     private SeekBar mRedBar;
     69     /**
     70      * Seekbar for green bar of tinting color.
     71      */
     72     private SeekBar mGreenBar;
     73     /**
     74      * Seekbar for blue bar of tinting color.
     75      */
     76     private SeekBar mBlueBar;
     77 
     78     /**
     79      * Text label for alpha component seekbar.
     80      */
     81     private TextView mAlphaText;
     82     /**
     83      * Text label for red component seekbar.
     84      */
     85     private TextView mRedText;
     86     /**
     87      * Text label for green component seekbar.
     88      */
     89     private TextView mGreenText;
     90     /**
     91      * Text label for blue component seekbar.
     92      */
     93     private TextView mBlueText;
     94 
     95     /**
     96      * Selector for blend type for color tinting.
     97      */
     98     private Spinner mBlendSpinner;
     99 
    100     /**
    101      * Computed color for tinting of drawable.
    102      */
    103     private int mHintColor;
    104 
    105     /**
    106      * Selected color tinting mode.
    107      */
    108     private PorterDuff.Mode mMode;
    109 
    110     /**
    111      * Identifier for state of blend mod spinner in state bundle.
    112      */
    113     private static final String STATE_BLEND = "DRAWABLETINTING_BLEND";
    114     /**
    115      * Identifier for state of alpha seek bar in state bundle.
    116      */
    117     private static final String STATE_ALPHA = "DRAWABLETINTING_ALPHA";
    118     /**
    119      * Identifier for state of red seek bar in state bundle.
    120      */
    121     private static final String STATE_RED = "DRAWABLETINTING_RED";
    122     /**
    123      * Identifier for state of green seek bar in state bundle.
    124      */
    125     private static final String STATE_GREEN = "DRAWABLETINTING_GREEN";
    126     /**
    127      * Identifier for state of blue seek bar in state bundle.
    128      */
    129     private static final String STATE_BLUE = "DRAWABLETINTING_BLUE";
    130 
    131     /**
    132      * Available tinting modes. Note that this array must be kept in sync with the
    133      * <code>blend_modes</code> string array that provides labels for these modes.
    134      */
    135     private static final PorterDuff.Mode[] MODES = new PorterDuff.Mode[]{
    136             PorterDuff.Mode.ADD,
    137             PorterDuff.Mode.CLEAR,
    138             PorterDuff.Mode.DARKEN,
    139             PorterDuff.Mode.DST,
    140             PorterDuff.Mode.DST_ATOP,
    141             PorterDuff.Mode.DST_IN,
    142             PorterDuff.Mode.DST_OUT,
    143             PorterDuff.Mode.DST_OVER,
    144             PorterDuff.Mode.LIGHTEN,
    145             PorterDuff.Mode.MULTIPLY,
    146             PorterDuff.Mode.OVERLAY,
    147             PorterDuff.Mode.SCREEN,
    148             PorterDuff.Mode.SRC,
    149             PorterDuff.Mode.SRC_ATOP,
    150             PorterDuff.Mode.SRC_IN,
    151             PorterDuff.Mode.SRC_OUT,
    152             PorterDuff.Mode.SRC_OVER,
    153             PorterDuff.Mode.XOR
    154     };
    155 
    156 
    157     @Override
    158     public void onCreate(Bundle savedInstanceState) {
    159         super.onCreate(savedInstanceState);
    160         setHasOptionsMenu(true);
    161     }
    162 
    163     @Override
    164     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    165         View v = inflater.inflate(R.layout.tinting_fragment, null);
    166 
    167         // Set a drawable as the image to display
    168         mImage = (ImageView) v.findViewById(R.id.image);
    169         mImage.setImageResource(R.drawable.btn_default_normal_holo);
    170 
    171         // Get text labels and seekbars for the four color components: ARGB
    172         mAlphaBar = (SeekBar) v.findViewById(R.id.alphaSeek);
    173         mAlphaText = (TextView) v.findViewById(R.id.alphaText);
    174         mGreenBar = (SeekBar) v.findViewById(R.id.greenSeek);
    175         mGreenText = (TextView) v.findViewById(R.id.greenText);
    176         mRedBar = (SeekBar) v.findViewById(R.id.redSeek);
    177         mRedText = (TextView) v.findViewById(R.id.redText);
    178         mBlueText = (TextView) v.findViewById(R.id.blueText);
    179         mBlueBar = (SeekBar) v.findViewById(R.id.blueSeek);
    180 
    181         // Set a listener to update tinted image when selections have changed
    182         mAlphaBar.setOnSeekBarChangeListener(mSeekBarListener);
    183         mRedBar.setOnSeekBarChangeListener(mSeekBarListener);
    184         mGreenBar.setOnSeekBarChangeListener(mSeekBarListener);
    185         mBlueBar.setOnSeekBarChangeListener(mSeekBarListener);
    186 
    187 
    188         // Set up the spinner for blend mode selection from a string array resource
    189         mBlendSpinner = (Spinner) v.findViewById(R.id.blendSpinner);
    190         SpinnerAdapter sa = ArrayAdapter.createFromResource(getActivity(),
    191                 R.array.blend_modes, android.R.layout.simple_spinner_dropdown_item);
    192         mBlendSpinner.setAdapter(sa);
    193         // Set a listener to update the tinted image when a blend mode is selected
    194         mBlendSpinner.setOnItemSelectedListener(mBlendListener);
    195         // Select the first item
    196         mBlendSpinner.setSelection(0);
    197         mMode = MODES[0];
    198 
    199         if (savedInstanceState != null) {
    200             // Restore the previous state if this fragment has been restored
    201             mBlendSpinner.setSelection(savedInstanceState.getInt(STATE_BLEND));
    202             mAlphaBar.setProgress(savedInstanceState.getInt(STATE_ALPHA));
    203             mRedBar.setProgress(savedInstanceState.getInt(STATE_RED));
    204             mGreenBar.setProgress(savedInstanceState.getInt(STATE_GREEN));
    205             mBlueBar.setProgress(savedInstanceState.getInt(STATE_BLUE));
    206         }
    207 
    208         // Apply the default blend mode and color
    209         updateTint(getColor(), getTintMode());
    210 
    211         return v;
    212     }
    213 
    214     @Override
    215     public void onSaveInstanceState(Bundle outState) {
    216         super.onSaveInstanceState(outState);
    217         Log.d(TAG, "state saved.");
    218         outState.putInt(STATE_BLEND, mBlendSpinner.getSelectedItemPosition());
    219         outState.putInt(STATE_ALPHA, mAlphaBar.getProgress());
    220         outState.putInt(STATE_RED, mRedBar.getProgress());
    221         outState.putInt(STATE_GREEN, mGreenBar.getProgress());
    222         outState.putInt(STATE_BLUE, mBlueBar.getProgress());
    223     }
    224 
    225     /**
    226      * Computes the {@link Color} value from selection on ARGB sliders.
    227      *
    228      * @return color computed from selected ARGB values
    229      */
    230     public int getColor() {
    231         final int alpha = mAlphaBar.getProgress();
    232         final int red = mRedBar.getProgress();
    233         final int green = mGreenBar.getProgress();
    234         final int blue = mBlueBar.getProgress();
    235 
    236         return Color.argb(alpha, red, green, blue);
    237     }
    238 
    239     /**
    240      * Returns the {@link android.graphics.PorterDuff.Mode} for the selected tint mode option.
    241      *
    242      * @return selected tint mode
    243      */
    244     public PorterDuff.Mode getTintMode() {
    245         return MODES[mBlendSpinner.getSelectedItemPosition()];
    246     }
    247 
    248     /**
    249      * Update the tint of the image with the color set in the seekbars and selected blend mode.
    250      * The seekbars are set to a maximum of 255, with one for each of the four components of the
    251      * ARGB color. (Alpha, Red, Green, Blue.) Once a color has been computed using
    252      * {@link Color#argb(int, int, int, int)}, it is set togethe with the blend mode on the background
    253      * image using
    254      * {@link android.widget.ImageView#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
    255      */
    256     public void updateTint(int color, PorterDuff.Mode mode) {
    257         // Set the color hint of the image: ARGB
    258         mHintColor = color;
    259 
    260         // Set the color tint mode based on the selection of the Spinner
    261         mMode = mode;
    262 
    263         // Log selection
    264         Log.d(TAG, String.format("Updating tint with color [ARGB: %d,%d,%d,%d] and mode [%s]",
    265                 Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color),
    266                 mode.toString()));
    267 
    268         // Apply the color tint for the selected tint mode
    269         mImage.setColorFilter(mHintColor, mMode);
    270 
    271         // Update the text for each label with the value of each channel
    272         mAlphaText.setText(getString(R.string.value_alpha, Color.alpha(color)));
    273         mRedText.setText(getString(R.string.value_red, Color.red(color)));
    274         mGreenText.setText(getString(R.string.value_green, Color.green(color)));
    275         mBlueText.setText(getString(R.string.value_blue, Color.blue(color)));
    276     }
    277 
    278     /**
    279      * Listener that updates the tint when a blend mode is selected.
    280      */
    281     private AdapterView.OnItemSelectedListener mBlendListener =
    282             new AdapterView.OnItemSelectedListener() {
    283 
    284                 @Override
    285                 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
    286                     // Selected a blend mode and update the tint of image
    287                     updateTint(getColor(), getTintMode());
    288                 }
    289 
    290                 @Override
    291                 public void onNothingSelected(AdapterView<?> adapterView) {
    292 
    293                 }
    294 
    295             };
    296 
    297     /**
    298      * Seekbar listener that updates the tinted color when the progress bar has changed.
    299      */
    300     private SeekBar.OnSeekBarChangeListener mSeekBarListener =
    301             new SeekBar.OnSeekBarChangeListener() {
    302                 @Override
    303                 public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
    304                     // Update the tinted color from all selections in the UI
    305                     updateTint(getColor(), getTintMode());
    306                 }
    307 
    308                 @Override
    309                 public void onStartTrackingTouch(SeekBar seekBar) {
    310                 }
    311 
    312                 @Override
    313                 public void onStopTrackingTouch(SeekBar seekBar) {
    314                 }
    315             };
    316 }
    317