/* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.drawabletinting; import android.graphics.Color; import android.graphics.PorterDuff; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TextView; import com.example.android.common.logger.Log; /** * Sample that shows tinting of Drawables programmatically and of Drawable resources in XML. * Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters. * A color state list is referenced as the tint color, which defines colors for different * states of a View (for example disabled/enabled, focused, pressed or selected). * Programmatically, tinting is applied to a Drawable through its "setColorFilter" method, with * a reference to a color and a PorterDuff blend mode. The color and blend mode can be * changed from the UI. * * @see android.graphics.drawable.Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode) * @see android.graphics.drawable.Drawable#setTint(android.content.res.ColorStateList, android.graphics.PorterDuff.Mode) */ public class DrawableTintingFragment extends Fragment { /** * String that identifies logging output from this Fragment. */ private static final String TAG = "DrawableTintingFragment"; /** * Image that tinting is applied to programmatically. */ private ImageView mImage; /** * Seekbar for alpha component of tinting color. */ private SeekBar mAlphaBar; /** * Seekbar for red component of tinting color. */ private SeekBar mRedBar; /** * Seekbar for green bar of tinting color. */ private SeekBar mGreenBar; /** * Seekbar for blue bar of tinting color. */ private SeekBar mBlueBar; /** * Text label for alpha component seekbar. */ private TextView mAlphaText; /** * Text label for red component seekbar. */ private TextView mRedText; /** * Text label for green component seekbar. */ private TextView mGreenText; /** * Text label for blue component seekbar. */ private TextView mBlueText; /** * Selector for blend type for color tinting. */ private Spinner mBlendSpinner; /** * Computed color for tinting of drawable. */ private int mHintColor; /** * Selected color tinting mode. */ private PorterDuff.Mode mMode; /** * Identifier for state of blend mod spinner in state bundle. */ private static final String STATE_BLEND = "DRAWABLETINTING_BLEND"; /** * Identifier for state of alpha seek bar in state bundle. */ private static final String STATE_ALPHA = "DRAWABLETINTING_ALPHA"; /** * Identifier for state of red seek bar in state bundle. */ private static final String STATE_RED = "DRAWABLETINTING_RED"; /** * Identifier for state of green seek bar in state bundle. */ private static final String STATE_GREEN = "DRAWABLETINTING_GREEN"; /** * Identifier for state of blue seek bar in state bundle. */ private static final String STATE_BLUE = "DRAWABLETINTING_BLUE"; /** * Available tinting modes. Note that this array must be kept in sync with the * blend_modes string array that provides labels for these modes. */ private static final PorterDuff.Mode[] MODES = new PorterDuff.Mode[]{ PorterDuff.Mode.ADD, PorterDuff.Mode.CLEAR, PorterDuff.Mode.DARKEN, PorterDuff.Mode.DST, PorterDuff.Mode.DST_ATOP, PorterDuff.Mode.DST_IN, PorterDuff.Mode.DST_OUT, PorterDuff.Mode.DST_OVER, PorterDuff.Mode.LIGHTEN, PorterDuff.Mode.MULTIPLY, PorterDuff.Mode.OVERLAY, PorterDuff.Mode.SCREEN, PorterDuff.Mode.SRC, PorterDuff.Mode.SRC_ATOP, PorterDuff.Mode.SRC_IN, PorterDuff.Mode.SRC_OUT, PorterDuff.Mode.SRC_OVER, PorterDuff.Mode.XOR }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.tinting_fragment, null); // Set a drawable as the image to display mImage = (ImageView) v.findViewById(R.id.image); mImage.setImageResource(R.drawable.btn_default_normal_holo); // Get text labels and seekbars for the four color components: ARGB mAlphaBar = (SeekBar) v.findViewById(R.id.alphaSeek); mAlphaText = (TextView) v.findViewById(R.id.alphaText); mGreenBar = (SeekBar) v.findViewById(R.id.greenSeek); mGreenText = (TextView) v.findViewById(R.id.greenText); mRedBar = (SeekBar) v.findViewById(R.id.redSeek); mRedText = (TextView) v.findViewById(R.id.redText); mBlueText = (TextView) v.findViewById(R.id.blueText); mBlueBar = (SeekBar) v.findViewById(R.id.blueSeek); // Set a listener to update tinted image when selections have changed mAlphaBar.setOnSeekBarChangeListener(mSeekBarListener); mRedBar.setOnSeekBarChangeListener(mSeekBarListener); mGreenBar.setOnSeekBarChangeListener(mSeekBarListener); mBlueBar.setOnSeekBarChangeListener(mSeekBarListener); // Set up the spinner for blend mode selection from a string array resource mBlendSpinner = (Spinner) v.findViewById(R.id.blendSpinner); SpinnerAdapter sa = ArrayAdapter.createFromResource(getActivity(), R.array.blend_modes, android.R.layout.simple_spinner_dropdown_item); mBlendSpinner.setAdapter(sa); // Set a listener to update the tinted image when a blend mode is selected mBlendSpinner.setOnItemSelectedListener(mBlendListener); // Select the first item mBlendSpinner.setSelection(0); mMode = MODES[0]; if (savedInstanceState != null) { // Restore the previous state if this fragment has been restored mBlendSpinner.setSelection(savedInstanceState.getInt(STATE_BLEND)); mAlphaBar.setProgress(savedInstanceState.getInt(STATE_ALPHA)); mRedBar.setProgress(savedInstanceState.getInt(STATE_RED)); mGreenBar.setProgress(savedInstanceState.getInt(STATE_GREEN)); mBlueBar.setProgress(savedInstanceState.getInt(STATE_BLUE)); } // Apply the default blend mode and color updateTint(getColor(), getTintMode()); return v; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d(TAG, "state saved."); outState.putInt(STATE_BLEND, mBlendSpinner.getSelectedItemPosition()); outState.putInt(STATE_ALPHA, mAlphaBar.getProgress()); outState.putInt(STATE_RED, mRedBar.getProgress()); outState.putInt(STATE_GREEN, mGreenBar.getProgress()); outState.putInt(STATE_BLUE, mBlueBar.getProgress()); } /** * Computes the {@link Color} value from selection on ARGB sliders. * * @return color computed from selected ARGB values */ public int getColor() { final int alpha = mAlphaBar.getProgress(); final int red = mRedBar.getProgress(); final int green = mGreenBar.getProgress(); final int blue = mBlueBar.getProgress(); return Color.argb(alpha, red, green, blue); } /** * Returns the {@link android.graphics.PorterDuff.Mode} for the selected tint mode option. * * @return selected tint mode */ public PorterDuff.Mode getTintMode() { return MODES[mBlendSpinner.getSelectedItemPosition()]; } /** * Update the tint of the image with the color set in the seekbars and selected blend mode. * The seekbars are set to a maximum of 255, with one for each of the four components of the * ARGB color. (Alpha, Red, Green, Blue.) Once a color has been computed using * {@link Color#argb(int, int, int, int)}, it is set togethe with the blend mode on the background * image using * {@link android.widget.ImageView#setColorFilter(int, android.graphics.PorterDuff.Mode)}. */ public void updateTint(int color, PorterDuff.Mode mode) { // Set the color hint of the image: ARGB mHintColor = color; // Set the color tint mode based on the selection of the Spinner mMode = mode; // Log selection Log.d(TAG, String.format("Updating tint with color [ARGB: %d,%d,%d,%d] and mode [%s]", Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color), mode.toString())); // Apply the color tint for the selected tint mode mImage.setColorFilter(mHintColor, mMode); // Update the text for each label with the value of each channel mAlphaText.setText(getString(R.string.value_alpha, Color.alpha(color))); mRedText.setText(getString(R.string.value_red, Color.red(color))); mGreenText.setText(getString(R.string.value_green, Color.green(color))); mBlueText.setText(getString(R.string.value_blue, Color.blue(color))); } /** * Listener that updates the tint when a blend mode is selected. */ private AdapterView.OnItemSelectedListener mBlendListener = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { // Selected a blend mode and update the tint of image updateTint(getColor(), getTintMode()); } @Override public void onNothingSelected(AdapterView adapterView) { } }; /** * Seekbar listener that updates the tinted color when the progress bar has changed. */ private SeekBar.OnSeekBarChangeListener mSeekBarListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { // Update the tinted color from all selections in the UI updateTint(getColor(), getTintMode()); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }; }