Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.taobao.weex.ui.animation; import android.animation.PropertyValuesHolder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; import android.text.TextUtils; import android.util.Pair; import android.util.Property; import android.view.View; import com.taobao.weex.WXEnvironment; import com.taobao.weex.common.Constants; import com.taobao.weex.ui.animation.CameraDistanceProperty; import com.taobao.weex.ui.animation.WXAnimationBean; import com.taobao.weex.utils.FunctionParser; import com.taobao.weex.utils.WXDataStructureUtil; import com.taobao.weex.utils.WXUtils; import com.taobao.weex.utils.WXViewUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Created by furture on 2017/10/24. */ public class TransformParser { public final static String WX_TRANSLATE = "translate"; public final static String WX_TRANSLATE_X = "translateX"; public final static String WX_TRANSLATE_Y = "translateY"; public final static String WX_ROTATE = "rotate"; public final static String WX_ROTATE_X = "rotateX"; public final static String WX_ROTATE_Y = "rotateY"; public final static String WX_SCALE = "scale"; public final static String WX_SCALE_X = "scaleX"; public final static String WX_SCALE_Y = "scaleY"; public final static String BACKGROUND_COLOR = Constants.Name.BACKGROUND_COLOR; public final static String WIDTH = Constants.Name.WIDTH; public final static String HEIGHT = Constants.Name.HEIGHT; public final static String TOP = "top"; public final static String BOTTOM = "bottom"; public final static String RIGHT = "right"; public final static String LEFT = "left"; public final static String CENTER = "center"; private static final String HALF = "50%"; private static final String FULL = "100%"; private static final String ZERO = "0%"; private static final String PX = "px"; private static final String DEG = "deg"; public static Map<String, List<Property<View, Float>>> wxToAndroidMap = new ArrayMap<>(); static { wxToAndroidMap.put(WX_TRANSLATE, Arrays.asList(View.TRANSLATION_X, View.TRANSLATION_Y)); wxToAndroidMap.put(WX_TRANSLATE_X, Collections.singletonList(View.TRANSLATION_X)); wxToAndroidMap.put(WX_TRANSLATE_Y, Collections.singletonList(View.TRANSLATION_Y)); wxToAndroidMap.put(WX_ROTATE, Collections.singletonList(View.ROTATION)); wxToAndroidMap.put(WX_ROTATE_X, Collections.singletonList(View.ROTATION_X)); wxToAndroidMap.put(WX_ROTATE_Y, Collections.singletonList(View.ROTATION_Y)); wxToAndroidMap.put(WX_SCALE, Arrays.asList(View.SCALE_X, View.SCALE_Y)); wxToAndroidMap.put(WX_SCALE_X, Collections.singletonList(View.SCALE_X)); wxToAndroidMap.put(WX_SCALE_Y, Collections.singletonList(View.SCALE_Y)); wxToAndroidMap.put(Constants.Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance())); wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap); } public static PropertyValuesHolder[] toHolders(Map<Property<View, Float>, Float> transformMap) { PropertyValuesHolder[] holders = new PropertyValuesHolder[transformMap.size()]; int i = 0; for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) { holders[i] = PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue()); i++; } return holders; } public static Map<Property<View, Float>, Float> parseTransForm(@Nullable String rawTransform, final int width, final int height, final int viewportW) { if (!TextUtils.isEmpty(rawTransform)) { FunctionParser<Property<View, Float>, Float> parser = new FunctionParser<>(rawTransform, new FunctionParser.Mapper<Property<View, Float>, Float>() { @Override public Map<Property<View, Float>, Float> map(String functionName, List<String> raw) { if (raw != null && !raw.isEmpty()) { if (wxToAndroidMap.containsKey(functionName)) { return convertParam(width, height, viewportW, wxToAndroidMap.get(functionName), raw); } } return new HashMap<>(); } private Map<Property<View, Float>, Float> convertParam(int width, int height, int viewportW, @NonNull List<Property<View, Float>> propertyList, @NonNull List<String> rawValue) { Map<Property<View, Float>, Float> result = WXDataStructureUtil .newHashMapWithExpectedSize(propertyList.size()); List<Float> convertedList = new ArrayList<>(propertyList.size()); if (propertyList.contains(View.ROTATION) || propertyList.contains(View.ROTATION_X) || propertyList.contains(View.ROTATION_Y)) { convertedList.addAll(parseRotationZ(rawValue)); } else if (propertyList.contains(View.TRANSLATION_X) || propertyList.contains(View.TRANSLATION_Y)) { convertedList .addAll(parseTranslation(propertyList, width, height, rawValue, viewportW)); } else if (propertyList.contains(View.SCALE_X) || propertyList.contains(View.SCALE_Y)) { convertedList.addAll(parseScale(propertyList.size(), rawValue)); } else if (propertyList.contains(CameraDistanceProperty.getInstance())) { convertedList.add(parseCameraDistance(rawValue)); } if (propertyList.size() == convertedList.size()) { for (int i = 0; i < propertyList.size(); i++) { result.put(propertyList.get(i), convertedList.get(i)); } } return result; } private List<Float> parseScale(int size, @NonNull List<String> rawValue) { List<Float> convertedList = new ArrayList<>(rawValue.size() * 2); List<Float> rawFloat = new ArrayList<>(rawValue.size()); for (String item : rawValue) { rawFloat.add(WXUtils.fastGetFloat(item)); } convertedList.addAll(rawFloat); if (size != 1 && rawValue.size() == 1) { convertedList.addAll(rawFloat); } return convertedList; } private @NonNull List<Float> parseRotationZ(@NonNull List<String> rawValue) { List<Float> convertedList = new ArrayList<>(1); int suffix; for (String raw : rawValue) { if ((suffix = raw.lastIndexOf(DEG)) != -1) { convertedList.add(WXUtils.fastGetFloat(raw.substring(0, suffix))); } else { convertedList.add((float) Math.toDegrees(Double.parseDouble(raw))); } } return convertedList; } /** * As "translate(50%, 25%)" or "translate(25px, 30px)" both are valid, * parsing translate is complicated than other method. * Add your waste time here if you try to optimize this method like {@link #parseScale(int, List)} * Time: 0.5h */ private List<Float> parseTranslation(List<Property<View, Float>> propertyList, int width, int height, @NonNull List<String> rawValue, int viewportW) { List<Float> convertedList = new ArrayList<>(2); String first = rawValue.get(0); if (propertyList.size() == 1) { parseSingleTranslation(propertyList, width, height, convertedList, first, viewportW); } else { parseDoubleTranslation(width, height, rawValue, convertedList, first, viewportW); } return convertedList; } private void parseSingleTranslation(List<Property<View, Float>> propertyList, int width, int height, List<Float> convertedList, String first, int viewportW) { if (propertyList.contains(View.TRANSLATION_X)) { convertedList.add(parsePercentOrPx(first, width, viewportW)); } else if (propertyList.contains(View.TRANSLATION_Y)) { convertedList.add(parsePercentOrPx(first, height, viewportW)); } } private void parseDoubleTranslation(int width, int height, @NonNull List<String> rawValue, List<Float> convertedList, String first, int viewportW) { String second; if (rawValue.size() == 1) { second = first; } else { second = rawValue.get(1); } convertedList.add(parsePercentOrPx(first, width, viewportW)); convertedList.add(parsePercentOrPx(second, height, viewportW)); } private Float parseCameraDistance(List<String> rawValue) { float ret = Float.MAX_VALUE; if (rawValue.size() == 1) { float value = WXViewUtils.getRealPxByWidth(WXUtils.getFloat(rawValue.get(0)), viewportW); float scale = WXEnvironment.getApplication().getResources() .getDisplayMetrics().density; if (!Float.isNaN(value) && value > 0) { ret = value * scale; } } return ret; } }); return parser.parse(); } return new LinkedHashMap<>(); } private static Pair<Float, Float> parsePivot(@Nullable String transformOrigin, int width, int height, int viewportW) { if (!TextUtils.isEmpty(transformOrigin)) { int firstSpace = transformOrigin.indexOf(FunctionParser.SPACE); if (firstSpace != -1) { int i = firstSpace; for (; i < transformOrigin.length(); i++) { if (transformOrigin.charAt(i) != FunctionParser.SPACE) { break; } } if (i < transformOrigin.length() && transformOrigin.charAt(i) != FunctionParser.SPACE) { List<String> list = new ArrayList<>(2); list.add(transformOrigin.substring(0, firstSpace).trim()); list.add(transformOrigin.substring(i, transformOrigin.length()).trim()); return parsePivot(list, width, height, viewportW); } } } return null; } private static Pair<Float, Float> parsePivot(@NonNull List<String> list, int width, int height, int viewportW) { return new Pair<>(parsePivotX(list.get(0), width, viewportW), parsePivotY(list.get(1), height, viewportW)); } private static float parsePivotX(String x, int width, int viewportW) { String value = x; if (WXAnimationBean.Style.LEFT.equals(x)) { value = ZERO; } else if (WXAnimationBean.Style.RIGHT.equals(x)) { value = FULL; } else if (WXAnimationBean.Style.CENTER.equals(x)) { value = HALF; } return parsePercentOrPx(value, width, viewportW); } private static float parsePivotY(String y, int height, int viewportW) { String value = y; if (WXAnimationBean.Style.TOP.equals(y)) { value = ZERO; } else if (WXAnimationBean.Style.BOTTOM.equals(y)) { value = FULL; } else if (WXAnimationBean.Style.CENTER.equals(y)) { value = HALF; } return parsePercentOrPx(value, height, viewportW); } private static float parsePercentOrPx(String raw, int unit, int viewportW) { final int precision = 1; int suffix; if ((suffix = raw.lastIndexOf(WXUtils.PERCENT)) != -1) { return parsePercent(raw.substring(0, suffix), unit, precision); } else if ((suffix = raw.lastIndexOf(PX)) != -1) { return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw.substring(0, suffix), precision), viewportW); } return WXViewUtils.getRealPxByWidth(WXUtils.fastGetFloat(raw, precision), viewportW); } private static float parsePercent(String percent, int unit, int precision) { return WXUtils.fastGetFloat(percent, precision) / 100 * unit; } }