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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.alibaba.weex.extend.component; import android.graphics.Color; import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.common.Constants; import com.taobao.weex.common.ICheckBindingScroller; import com.taobao.weex.common.OnWXScrollListener; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.animation.WXAnimationBean; import com.taobao.weex.ui.component.Scrollable; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXDiv; import com.taobao.weex.ui.component.WXVContainer; import com.taobao.weex.ui.component.list.BasicListComponent; import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList; import com.taobao.weex.ui.view.listview.WXRecyclerView; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXResourceUtils; import java.util.ArrayList; /** * Created by zhengshihan on 2017/5/3. */ public class WXParallax extends WXDiv implements OnWXScrollListener, ICheckBindingScroller { public final static String WX_TRANSFORM = "transform"; public final static String WX_OPACITY = "opacity"; public static final String PARALLAX = "parallax"; public static final String BINDING_SCROLLER = "bindingScroller"; ArrayList<TransformCreator> mTransformPropArrayList = new ArrayList<>(); BackgroundColorCreator mBackgroundColor; String mBindingRef = ""; WXComponent mBindingComponent; private int mBackGroundColor = 0; private float mOffsetY = 0; public WXParallax(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) { super(instance, dom, parent); initTransform(dom.getAttrs().get(WX_TRANSFORM)); initOpacity(dom.getAttrs().get(Constants.Name.OPACITY)); initBackgroundColor(dom.getAttrs().get(Constants.Name.BACKGROUND_COLOR)); mBindingRef = (String) (dom.getAttrs().get(BINDING_SCROLLER)); instance.registerOnWXScrollListener(this); } private void initBackgroundColor(Object obj) { if (obj == null) return; if (obj instanceof JSONObject) { mBackgroundColor = new BackgroundColorCreator(); JSONObject object = (JSONObject) obj; JSONArray in = object.getJSONArray("in"); mBackgroundColor.input = new int[in.size()]; for (int i = 0; i < in.size(); i++) { mBackgroundColor.input[i] = in.getInteger(i); } JSONArray out = object.getJSONArray("out"); mBackgroundColor.output = new int[out.size()]; for (int i = 0; i < out.size(); i++) { String colorStr = out.getString(i); mBackgroundColor.output[i] = WXResourceUtils.getColor(colorStr); } } } private void initOpacity(Object obj) { if (obj == null) return; if (obj instanceof JSONObject) { mTransformPropArrayList.add(new TransformCreator(WX_OPACITY, (JSONObject) obj)); } } private void initTransform(Object propStr) { if (propStr == null) { WXLogUtils.w("WXParallax initAnimation propStr ==null"); return; } JSONArray jsonObject; if (propStr instanceof JSONArray) { jsonObject = (JSONArray) propStr; for (int i = 0; i < jsonObject.size(); i++) { JSONObject object = jsonObject.getJSONObject(i); mTransformPropArrayList.add(i, new TransformCreator(object.getString("type"), object)); } } } @Override public boolean isNeedScroller(String ref, Object option) { mBindingRef = (String) (getDomObject().getAttrs().get(BINDING_SCROLLER)); if (TextUtils.isEmpty(mBindingRef)) { WXComponent root = getInstance().getRootComponent(); if (root != null && root instanceof WXVContainer) { Scrollable scrollable = root.getFirstScroller(); if (scrollable != null) { mBindingRef = scrollable.getRef(); } } } if (!TextUtils.isEmpty(mBindingRef) && !TextUtils.isEmpty(ref) && ref.equals(mBindingRef)) { return true; } return false; } @Override public void onScrolled(View view, int dx, int dy) { if (ViewCompat.isInLayout(view)) { if (mBindingComponent == null && mBindingRef != null) { mBindingComponent = findComponent(mBindingRef); } if (mBindingComponent instanceof BasicListComponent && view instanceof RecyclerView) { BasicListComponent listComponent = (BasicListComponent) mBindingComponent; mOffsetY = Math.abs(listComponent.calcContentOffset((RecyclerView) view)); } else if (mBindingComponent instanceof WXRecyclerTemplateList && view instanceof RecyclerView) { WXRecyclerTemplateList listComponent = (WXRecyclerTemplateList) mBindingComponent; mOffsetY = Math.abs(listComponent.calcContentOffset((RecyclerView) view)); } } else { mOffsetY = mOffsetY + dy; } AnimationSet animationSet = new AnimationSet(true); boolean hasAnimation = false; for (int i = 0; i < mTransformPropArrayList.size(); i++) { TransformCreator creator = mTransformPropArrayList.get(i); Animation animation = creator.getAnimation(dx, dy); if (animation != null) { animationSet.addAnimation(animation); hasAnimation = true; } } if (hasAnimation) { animationSet.setFillAfter(true); if (getHostView() != null) { getHostView().startAnimation(animationSet); } } if (mBackgroundColor != null) { int color = mBackgroundColor.getColor(dx, dy); if (mBackGroundColor != color) { getHostView().setBackgroundColor(color); mBackGroundColor = color; } } } @Override public void onScrollStateChanged(View view, int x, int y, int newState) { } private class BackgroundColorCreator { int[] input; int[] output; int getColor(int XDelta, int YDelta) { if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax:getColor: XDelta" + XDelta + " YDelta:" + YDelta + " mOffsetY" + mOffsetY); } int r1, g1, b1; if (mOffsetY > input[1]) { return output[1]; } if (mOffsetY < input[0]) { return output[0]; } r1 = Color.red(output[0]) + (int) (mOffsetY - input[0]) * (Color.red(output[1]) - Color.red(output[0])) / (input[1] - input[0]); g1 = Color.green(output[0]) + (int) (mOffsetY - input[0]) * (Color.green(output[1]) - Color.green(output[0])) / (input[1] - input[0]); b1 = Color.blue(output[0]) + (int) (mOffsetY - input[0]) * (Color.blue(output[1]) - Color.blue(output[0])) / (input[1] - input[0]); if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax:getColor: r1" + r1 + " g1:" + g1 + " b1:" + b1); } return Color.rgb(r1, g1, b1); } } private class TransformCreator { String transformType; float[] input, output; float fromTranslateX, fromTranslateY; float fromScaleX, fromScaleY; float fromRotate, fromOpacity; TransformCreator(String type, JSONObject object) { transformType = type; JSONArray in = object.getJSONArray("in"); input = parseParamArray(in); JSONArray out = object.getJSONArray("out"); output = parseParamArray(out); switch (transformType) { case WXAnimationBean.Style.WX_TRANSLATE: fromTranslateX = output[0]; fromTranslateY = output[1]; break; case WXAnimationBean.Style.WX_SCALE: fromScaleX = output[0]; fromScaleY = output[1]; break; case WXAnimationBean.Style.WX_ROTATE: fromRotate = output[0]; break; case WX_OPACITY: fromOpacity = output[0]; break; } } float[] parseParamArray(JSONArray in) { int size = in.size(); float[] param = new float[size]; for (int j = 0; j < size; j++) { param[j] = in.getFloatValue(j); } return param; } @Nullable Animation getAnimation(float XDelta, float YDelta) { float offset = mOffsetY; if (offset > input[1]) { offset = input[1]; } if (offset < input[0]) { offset = input[0]; } float toTranslateX, toTranslateY, toOpacity, toScaleX, toScaleY, toRotate; Animation animation = null; if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax", "type:" + transformType + " XDelta:" + XDelta + " YDelta:" + YDelta); } switch (transformType) { case WXAnimationBean.Style.WX_TRANSLATE: toTranslateX = output[0] + (output[2] - output[0]) * (offset - input[0]) / (input[1] - input[0]); toTranslateY = output[1] + (output[3] - output[1]) * (offset - input[0]) / (input[1] - input[0]); if (fromTranslateX == toTranslateX && fromTranslateY == toTranslateY) { return null; } animation = new TranslateAnimation(fromTranslateX, toTranslateX, fromTranslateY, toTranslateY); fromTranslateX = toTranslateX; fromTranslateY = toTranslateY; if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax", "XDelta:" + XDelta + " YDelta:" + YDelta); WXLogUtils.d("WXParallax", " fromTranslateX:" + fromTranslateX + " toTranslateX:" + toTranslateX + " fromTranslateY:" + fromTranslateY + " toTranslateY:" + toTranslateY); } break; case WXAnimationBean.Style.WX_SCALE: toScaleX = output[0] + (output[2] - output[0]) * (offset - input[0]) / (input[1] - input[0]); toScaleY = output[1] + (output[3] - output[1]) * (offset - input[0]) / (input[1] - input[0]); if (fromScaleX == toScaleX && fromScaleY == toScaleY) { return null; } animation = new ScaleAnimation(fromScaleX, toScaleX, fromScaleY, toScaleY); if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax", " fromScaleX:" + fromScaleX + " toScaleX:" + toScaleX + " fromScaleY:" + fromScaleY + " toScaleY:" + toScaleY); } fromScaleX = toScaleX; fromScaleY = toScaleY; break; case WXAnimationBean.Style.WX_ROTATE: toRotate = output[0] + (output[1] - output[0]) * (offset - input[0]) / (input[1] - input[0]); if (fromRotate == toRotate) { return null; } animation = new RotateAnimation(fromRotate, toRotate, output[2], output[3]); fromRotate = toRotate; break; case WX_OPACITY: toOpacity = output[0] + (output[1] - output[0]) * (offset - input[0]) / (input[1] - input[0]); if (fromOpacity == toOpacity) { return null; } setOpacity(toOpacity); // animation = new AlphaAnimation(fromOpacity, toOpacity); if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("WXParallax", "opacity fromOpacity:" + fromOpacity + " toOpacity:" + toOpacity); } fromOpacity = toOpacity; break; } return animation; } } }