Skip to content

Most visited

Recently visited

navigation
DrawableTinting / src / com.example.android.drawabletinting /

DrawableTintingFragment.java

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