blob: fe425b7201e1d42396aa0c499f17303e555cc352 [file] [log] [blame]
/*
* 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.common.Constants.Name;
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.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class WXAnimationBean {
public final static String LINEAR = "linear";
public final static String EASE_IN_OUT = "ease-in-out";
public final static String EASE_IN = "ease-in";
public final static String EASE_OUT = "ease-out";
public final static String CUBIC_BEZIER = "cubic-bezier";
public final static int NUM_CUBIC_PARAM = 4;
public long delay;
public long duration;
public String timingFunction;
public @Nullable Style styles;
public boolean needLayout;
public static class Style {
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_SCALE_X = "scaleX";
public final static String WX_SCALE_Y = "scaleY";
public final static String WX_SCALE = "scale";
public final static String WX_ROTATE_X ="rotateX";
public final static String WX_ROTATE_Y ="rotateY";
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<>();
private static Map<Property<View, Float>, Float> defaultMap= 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(Name.PERSPECTIVE, Collections.singletonList(CameraDistanceProperty.getInstance()));
wxToAndroidMap = Collections.unmodifiableMap(wxToAndroidMap);
defaultMap.put(View.TRANSLATION_X, 0f);
defaultMap.put(View.TRANSLATION_Y, 0f);
defaultMap.put(View.SCALE_X, 1f);
defaultMap.put(View.SCALE_Y, 1f);
defaultMap.put(View.ROTATION, 0f);
defaultMap.put(View.ROTATION_X, 0f);
defaultMap.put(View.ROTATION_Y, 0f);
}
public String opacity;
public String backgroundColor;
public String width;
public String height;
public String transform;
public String transformOrigin;
private Map<Property<View, Float>, Float> transformMap = new LinkedHashMap<>();
private Pair<Float, Float> pivot;
private List<PropertyValuesHolder> holders=new LinkedList<>();
private float cameraDistance = Float.MAX_VALUE;
private static Map<Property<View,Float>, Float> parseTransForm(@Nullable String rawTransform, final int width,
final int height,final int viewportW) {
return TransformParser.parseTransForm(rawTransform, width, height, viewportW);
}
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;
}
private void resetToDefaultIfAbsent() {
for (Entry<Property<View, Float>, Float> entry : defaultMap.entrySet()) {
if (!transformMap.containsKey(entry.getKey())) {
transformMap.put(entry.getKey(), entry.getValue());
}
}
}
public @Nullable Pair<Float, Float> getPivot() {
return pivot;
}
public void init(@Nullable String transformOrigin,@Nullable String rawTransform,
final int width, final int height,int viewportW){
pivot = parsePivot(transformOrigin,width,height,viewportW);
transformMap.putAll(parseTransForm(rawTransform,width,height,viewportW));
resetToDefaultIfAbsent();
if (transformMap.containsKey(CameraDistanceProperty.getInstance())) {
cameraDistance = transformMap.remove(CameraDistanceProperty.getInstance());
}
initHolders();
}
/**
* Use this method to init if you already have a list of Property
* The key is something like {@link View#TRANSLATION_X} and the value is a {@link Pair},
* of which the first is beginning value and the second is ending value.
* @param styles a list of Property
*/
public void init(@NonNull Map<Property<View, Float>, Pair<Float, Float>> styles){
for(Entry<Property<View, Float>, Pair<Float, Float>> entry:styles.entrySet()){
holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue().first, entry.getValue().second));
}
}
private void initHolders(){
for (Map.Entry<Property<View, Float>, Float> entry : transformMap.entrySet()) {
holders.add(PropertyValuesHolder.ofFloat(entry.getKey(), entry.getValue()));
}
if (!TextUtils.isEmpty(opacity)) {
holders.add(PropertyValuesHolder.ofFloat(View.ALPHA, WXUtils.fastGetFloat(opacity, 3)));
}
}
public List<PropertyValuesHolder> getHolders(){
return holders;
}
public float getCameraDistance(){
return cameraDistance;
}
}
}