/* * Created by LuaView. * Copyright (c) 2017, Alibaba Group. All rights reserved. * * This source code is licensed under the MIT. * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree. */ package com.taobao.luaview.view; import android.content.Context; import android.view.KeyEvent; import android.view.View; import android.widget.RelativeLayout; import com.facebook.csslayout.CSSLayoutContext; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.Spacing; import com.taobao.luaview.userdata.ui.UDView; import com.taobao.luaview.userdata.ui.UDViewGroup; import com.taobao.luaview.util.LuaViewUtil; import com.taobao.luaview.view.foreground.ForegroundRelativeLayout; import com.taobao.luaview.view.interfaces.ILVViewGroup; import org.luaj.vm2.Globals; import org.luaj.vm2.LuaValue; import org.luaj.vm2.Varargs; import java.util.ArrayList; /** * LuaView-ViewGroup * 容器类 * * @author song * @date 15/8/20 */ public class LVViewGroup<T extends UDViewGroup> extends ForegroundRelativeLayout implements ILVViewGroup { protected T mLuaUserdata; /** * Flexbox attributes */ private ArrayList<UDView> mChildNodeViews; private CSSNode mCSSNode; private CSSLayoutContext mLayoutContext; public LVViewGroup(Globals globals, LuaValue metaTable, Varargs varargs) { this(globals != null ? globals.getContext() : null, globals, metaTable, varargs); } public LVViewGroup(Context context, Globals globals, LuaValue metaTable, Varargs varargs) { super(context); this.mLuaUserdata = createUserdata(globals, metaTable, varargs); //改在UDViewGroup中设置,减少影响面 // this.setFocusableInTouchMode(true);//需要设置,否则onKeyUp等事件无法监听,排查是否会带来其他问题(点击的时候需要点击两下) // this.setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS); // this.setClipChildren(false); } public CSSNode getCssNode() { if (mCSSNode == null) { mCSSNode = new CSSNode(); } return mCSSNode; } private CSSLayoutContext getLayoutContext() { if (mLayoutContext == null) { mLayoutContext = new CSSLayoutContext(); } return mLayoutContext; } /** * create user data * * @param globals * @param metaTable * @param varargs * @return */ public T createUserdata(Globals globals, LuaValue metaTable, Varargs varargs) { return (T) (new UDViewGroup(this, globals, metaTable, varargs)); } @Override public T getUserdata() { return mLuaUserdata; } public void show() { LVViewGroup.this.setVisibility(View.VISIBLE); } public void hide() { LVViewGroup.this.setVisibility(View.GONE); } //-------------------------------------------显示回调-------------------------------------------- @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); if (visibility == View.VISIBLE) { mLuaUserdata.callOnShow(); } else {//这里会有 INVISIBLE 和 GONE 两种状态,INVISIBLE 也会调用,从后台进入的时候会调用一次 INVISIBLE 接着调用 VISIBLE mLuaUserdata.callOnHide(); } } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { LuaValue result = mLuaUserdata != null ? mLuaUserdata.callOnBack() : LuaValue.FALSE; return result != null && result.optboolean(false); } return super.onKeyUp(keyCode, event); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (mLuaUserdata != null) { mLuaUserdata.callOnLayout(); } } /** * Flexbox account */ public void setChildNodeViews(ArrayList<UDView> childNodeViews) { // diff old and new if (mChildNodeViews == childNodeViews) { return; } // remove all the old views clearChildNodeViews(); // set the new nodes mChildNodeViews = childNodeViews; // enum array and add into it generateNodeViewTree(); } private void clearChildNodeViews() { if (mChildNodeViews == null) { return; } int childNodeViewsCount = mChildNodeViews.size(); for (int i = 0; i < childNodeViewsCount; i++) { UDView nodeView = mChildNodeViews.get(i); View view = nodeView.getView(); removeView(view); } getCssNode().resetChildren(); } private void generateNodeViewTree() { if (mChildNodeViews == null) { return; } int childNodeViewsCount = mChildNodeViews.size(); for (int i = 0; i < childNodeViewsCount; i++) { UDView nodeView = mChildNodeViews.get(i); View view = nodeView.getView(); LuaViewUtil.addView(this, view, null); getCssNode().addChild(nodeView.getCssNode()); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mChildNodeViews == null || mChildNodeViews.size() == 0 || getCssNode().getParent() != null) { return; } measureChildNode(widthMeasureSpec, heightMeasureSpec); getCssNode().calculateLayout(getLayoutContext()); assignNodeLayoutParams(); } private void measureChildNode(int widthMeasureSpec, int heightMeasureSpec) { int childNodeViewsCount = mChildNodeViews.size(); for (int i = 0; i < childNodeViewsCount; i++) { UDView nodeView = mChildNodeViews.get(i); View view = nodeView.getView(); CSSNode node = nodeView.getCssNode(); if (node.getSizeToFit()) { int margins = (int) (node.getMargin().get(Spacing.LEFT) + node.getMargin().get(Spacing.RIGHT)); measureChild(view, widthMeasureSpec - margins, heightMeasureSpec); node.setNoDirtyStyleWidth(view.getMeasuredWidth()); node.setNoDirtyStyleHeight(view.getMeasuredHeight()); } if (view instanceof LVViewGroup) { LVViewGroup viewGroup = (LVViewGroup) view; if (viewGroup.getCssNode().getChildCount() > 0) { viewGroup.measureChildNode(widthMeasureSpec, heightMeasureSpec); } } } } private void assignNodeLayoutParams() { int childNodeViewsCount = mChildNodeViews.size(); for (int i = 0; i < childNodeViewsCount; i++) { UDView nodeView = mChildNodeViews.get(i); View view = nodeView.getView(); CSSNode node = nodeView.getCssNode(); if (view != null && node != null) { int x = (int) node.getLayoutX(); int y = (int) node.getLayoutY(); int width = (int) node.getLayoutWidth(); int height = (int) node.getLayoutHeight(); RelativeLayout.LayoutParams lParams = (LayoutParams) view.getLayoutParams(); if (lParams == null) { lParams = new RelativeLayout.LayoutParams(width, height); } else { lParams.width = width; lParams.height = height; } lParams.setMargins(x, y, 0, 0); view.setLayoutParams(lParams); if (view instanceof LVViewGroup) { LVViewGroup viewGroup = (LVViewGroup) view; if (viewGroup.getCssNode().getChildCount() > 0) { viewGroup.assignNodeLayoutParams(); } } } } } }