/******************************************************************************* * Copyright 2012-present Pixate, Inc. * * 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.pixate.freestyle.styling.adapters; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import android.graphics.Matrix; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import com.pixate.freestyle.annotations.PXDocElement; import com.pixate.freestyle.annotations.PXDocProperty; import com.pixate.freestyle.cg.math.PXDimension; import com.pixate.freestyle.styling.PXDeclaration; import com.pixate.freestyle.styling.PXRuleSet; import com.pixate.freestyle.styling.stylers.PXGenericStyler; import com.pixate.freestyle.styling.stylers.PXStyler; import com.pixate.freestyle.styling.stylers.PXStylerBase.PXDeclarationHandler; import com.pixate.freestyle.styling.stylers.PXStylerContext; import com.pixate.freestyle.styling.virtualAdapters.PXVirtualImageViewImageAdapter; import com.pixate.freestyle.styling.virtualStyleables.PXVirtualImageViewImage; import com.pixate.freestyle.util.PXLog; /** * A style adapter for {@link ImageView} widgets. This adapter supports the * regular view styling properties, plus a few special properties that are * unique for the {@link ImageView}. * * <pre> * - scale-type: center | center-crop | center-inside | fit-center | fit-end | fit-start | fit-xy | matrix * - max-height: px * - max-width: px * - view-bounds: adjust | none * - tint: color * - transform: matrix (inherited from the view styles, but used here when the scale-type is set to 'matrix') * </pre> * * For example: * * <pre> * .imageView { * tint: #450022FF; * transform: matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0); * scale-type: matrix; * } * </pre> * * And to set the image properties (virtual child of 'image'): * * <pre> * .imageView image { * background-image: url(mic-on.svg); * background-size: 300px; * } * * .imageView image:pressed { * background-image: url(mic-off.svg); * background-size: 300px; * } * </pre> * * @author Shalom Gibly */ @PXDocElement(properties = { @PXDocProperty(name = "scale-type", syntax = "center | center-crop | center-inside | fit-center | fit-end | fit-start | fit-xy | matrix"), @PXDocProperty(name = "max-height", syntax = "<length>"), @PXDocProperty(name = "max-width", syntax = "<length>"), @PXDocProperty(name = "view-bounds", syntax = "adjust"), @PXDocProperty(name = "tint", syntax = "<color>") }) public class PXImageViewStyleAdapter extends PXViewStyleAdapter { private static String TAG = PXVirtualImageViewImageAdapter.class.getSimpleName(); private static String ELEMENT_NAME = "image-view"; private static PXImageViewStyleAdapter instance; /** * Returns an instance of this {@link PXImageViewStyleAdapter} */ public static PXImageViewStyleAdapter getInstance() { synchronized (PXImageViewStyleAdapter.class) { if (instance == null) { instance = new PXImageViewStyleAdapter(); } } return instance; } protected PXImageViewStyleAdapter() { } @Override protected List<PXStyler> createStylers() { List<PXStyler> stylers = super.createStylers(); // Append the ImageView stylers Map<String, PXDeclarationHandler> handlers = new HashMap<String, PXDeclarationHandler>(1); handlers.put("scale-type", new PXDeclarationHandler() { @Override public void process(PXDeclaration declaration, PXStylerContext stylerContext) { String value = declaration.getStringValue(); if (value != null) { // get the match from the scale-types enum value = value.replaceAll("-", "_").toUpperCase(Locale.US); ScaleType type = ScaleType.valueOf(value); if (type != null) { ImageView view = (ImageView) stylerContext.getStyleable(); view.setScaleType(type); } else { PXLog.e(TAG, "Unknown ImageView scale-type '%s'", value); } } } }); handlers.put("max-height", new PXDeclarationHandler() { @Override public void process(PXDeclaration declaration, PXStylerContext stylerContext) { PXDimension height = declaration.getLengthValue(); if (height != null) { ImageView view = (ImageView) stylerContext.getStyleable(); view.setMaxHeight((int) Math.ceil(height.getNumber())); } else { PXLog.e(TAG, "Unknown ImageView max-height '%s'", declaration.getStringValue()); } } }); handlers.put("max-width", new PXDeclarationHandler() { @Override public void process(PXDeclaration declaration, PXStylerContext stylerContext) { PXDimension width = declaration.getLengthValue(); if (width != null) { ImageView view = (ImageView) stylerContext.getStyleable(); view.setMaxWidth((int) Math.ceil(width.getNumber())); } else { PXLog.e(TAG, "Unknown ImageView max-width '%s'", declaration.getStringValue()); } } }); handlers.put("view-bounds", new PXDeclarationHandler() { @Override public void process(PXDeclaration declaration, PXStylerContext stylerContext) { String viewBounds = declaration.getStringValue(); if (viewBounds != null) { ImageView view = (ImageView) stylerContext.getStyleable(); view.setAdjustViewBounds("adjust".equals(viewBounds)); } else { PXLog.e(TAG, "Unknown ImageView view-bounds '%s'", viewBounds); } } }); handlers.put("tint", new PXDeclarationHandler() { @Override public void process(PXDeclaration declaration, PXStylerContext stylerContext) { Integer colorValue = declaration.getColorValue(); if (colorValue != null) { ImageView view = (ImageView) stylerContext.getStyleable(); view.setColorFilter(colorValue); } else { PXLog.e(TAG, "Unknown ImageView tint '%s'", declaration.getStringValue()); } } }); stylers.add(new PXGenericStyler(handlers)); return stylers; } /* * (non-Javadoc) * @see * com.pixate.freestyle.styling.adapters.PXViewStyleAdapter#getElementName * (java.lang.Object) */ public String getElementName(Object object) { return ELEMENT_NAME; } /* * (non-Javadoc) * @see * com.pixate.freestyle.styling.adapters.PXStyleAdapter#getVirtualChildren * (java.lang.Object) */ @Override protected List<Object> getVirtualChildren(Object styleable) { List<Object> superVirtuals = super.getVirtualChildren(styleable); List<Object> result = new ArrayList<Object>(superVirtuals.size() + 1); result.addAll(superVirtuals); result.add(new PXVirtualImageViewImage(styleable)); return result; } /* * (non-Javadoc) * @see * com.pixate.freestyle.styling.adapters.PXViewStyleAdapter#updateStyle(java * .util.List, java.util.List) */ @Override public boolean updateStyle(List<PXRuleSet> ruleSets, List<PXStylerContext> contexts) { // Check for the Matrix in the contexts. ImageView view = (ImageView) contexts.get(0).getStyleable(); // Check if we have a transformation that we can use. We can only have // one transformation, so look for one in each of the contexts. Matrix matrix = null; for (PXStylerContext context : contexts) { matrix = context.getTransform(); if (matrix != null) { break; } } if (matrix != null) { view.setImageMatrix(matrix); } return super.updateStyle(ruleSets, contexts); } /* * (non-Javadoc) * @see com.pixate.freestyle.styling.adapters.PXViewStyleAdapter# * createAdditionalStates (int) */ @Override public int[][] createAdditionalDrawableStates(int initialValue) { List<int[]> states = new ArrayList<int[]>(4); // check for some special cases. switch (initialValue) { case android.R.attr.state_pressed: states.add(new int[] { android.R.attr.state_focused, android.R.attr.state_pressed }); states.add(new int[] { -android.R.attr.state_focused, android.R.attr.state_pressed }); break; case android.R.attr.drawable: // add anything that will be treated as the default. states.add(new int[] { -android.R.attr.state_focused, android.R.attr.state_enabled }); states.add(new int[] { android.R.attr.state_focused, android.R.attr.state_enabled }); states.add(new int[] { android.R.attr.state_focused }); states.add(new int[] {}); default: break; } states.add(new int[] { initialValue }); return states.toArray(new int[states.size()][]); } }