feat(ui): supports label grid

This commit is contained in:
hyb1996 2018-03-30 17:37:31 +08:00
parent 47faa1f69e
commit af5bf8ecf2
13 changed files with 176 additions and 17 deletions

View File

@ -0,0 +1,20 @@
"ui";
ui.layout(
<frame bg="#79bd9a">
<grid id="icons" spanCount="4">
<img src="@drawable/{{this}}" h="80" margin="12" bg="?selectableItemBackgroundBorderless"/>
</grid>
</frame>
);
//所有内置图标名称
var icons = ["ic_add_black_48dp", "ic_add_box_black_48dp", "ic_add_box_white_48dp", "ic_add_circle_black_48dp", "ic_add_circle_outline_black_48dp", "ic_add_circle_outline_white_48dp", "ic_add_circle_white_48dp", "ic_add_to_photos_white_48dp", "ic_add_white_48dp", "ic_adjust_black_48dp", "ic_alarm_white_48dp", "ic_archive_black_48dp", "ic_archive_white_48dp", "ic_assignment_returned_black_48dp", "ic_assignment_returned_white_48dp", "ic_assignment_return_black_48dp", "ic_assignment_return_white_48dp", "ic_assignment_turned_in_black_48dp", "ic_assignment_white_48dp", "ic_assistant_photo_white_48dp", "ic_audiotrack_white_48dp", "ic_autorenew_black_48dp", "ic_autorenew_white_48dp", "ic_backspace_black_48dp", "ic_backspace_white_48dp", "ic_backup_black_48dp", "ic_backup_white_48dp", "ic_block_black_48dp", "ic_block_white_48dp", "ic_blur_linear_black_48dp", "ic_blur_on_black_48dp", "ic_blur_on_white_48dp", "ic_book_black_48dp", "ic_brightness_3_white_48dp", "ic_brightness_5_white_48dp", "ic_brightness_7_black_48dp", "ic_broken_image_black_48dp", "ic_broken_image_white_48dp", "ic_brush_black_48dp", "ic_burst_mode_black_48dp", "ic_burst_mode_white_48dp", "ic_camera_alt_white_48dp", "ic_camera_enhance_black_48dp", "ic_camera_enhance_white_48dp", "ic_camera_front_white_48dp", "ic_camera_roll_black_48dp", "ic_card_giftcard_black_48dp", "ic_card_giftcard_white_48dp", "ic_card_membership_black_48dp", "ic_card_membership_white_48dp", "ic_card_travel_black_48dp", "ic_card_travel_white_48dp", "ic_center_focus_weak_white_48dp", "ic_change_history_black_48dp", "ic_class_white_48dp", "ic_clear_black_48dp", "ic_clear_white_48dp", "ic_code_black_48dp", "ic_collections_bookmark_white_48dp", "ic_colorize_black_48dp", "ic_compare_white_48dp", "ic_content_copy_black_48dp", "ic_content_copy_white_48dp", "ic_content_cut_black_48dp", "ic_content_cut_white_48dp", "ic_content_paste_black_48dp", "ic_content_paste_white_48dp", "ic_copyright_white_48dp", "ic_create_black_48dp", "ic_create_white_48dp", "ic_credit_card_black_48dp", "ic_credit_card_white_48dp", "ic_crop_16_9_white_48dp", "ic_crop_7_5_white_48dp", "ic_crop_din_white_48dp", "ic_crop_landscape_black_48dp", "ic_crop_portrait_black_48dp", "ic_crop_square_white_48dp", "ic_dashboard_black_48dp", "ic_dashboard_white_48dp", "ic_date_range_black_48dp", "ic_date_range_white_48dp", "ic_dehaze_white_48dp", "ic_delete_black_48dp", "ic_delete_sweep_black_48dp", "ic_delete_sweep_white_48dp", "ic_donut_small_white_48dp", "ic_drafts_black_48dp", "ic_drafts_white_48dp", "ic_edit_black_48dp", "ic_event_seat_white_48dp", "ic_exit_to_app_white_48dp", "ic_exposure_neg_1_black_48dp", "ic_exposure_neg_1_white_48dp", "ic_exposure_neg_2_white_48dp", "ic_exposure_plus_1_black_48dp", "ic_exposure_plus_2_white_48dp", "ic_exposure_white_48dp", "ic_exposure_zero_black_48dp", "ic_favorite_black_48dp", "ic_favorite_border_black_48dp", "ic_favorite_border_white_48dp", "ic_filter_1_black_48dp", "ic_filter_1_white_48dp", "ic_filter_3_black_48dp", "ic_filter_3_white_48dp", "ic_filter_4_white_48dp", "ic_filter_6_black_48dp", "ic_filter_6_white_48dp", "ic_filter_7_white_48dp", "ic_filter_8_black_48dp", "ic_filter_9_plus_black_48dp", "ic_filter_b_and_w_black_48dp", "ic_filter_center_focus_white_48dp", "ic_filter_list_black_48dp", "ic_filter_list_white_48dp", "ic_flag_black_48dp", "ic_flag_white_48dp", "ic_flash_off_black_48dp", "ic_flip_black_48dp", "ic_font_download_black_48dp", "ic_font_download_white_48dp", "ic_forward_black_48dp", "ic_forward_white_48dp", "ic_gesture_black_48dp", "ic_gesture_white_48dp", "ic_grain_black_48dp", "ic_grid_off_white_48dp", "ic_grid_on_black_48dp", "ic_hdr_off_white_48dp", "ic_hdr_strong_black_48dp", "ic_hdr_strong_white_48dp", "ic_healing_black_48dp", "ic_history_black_48dp", "ic_history_white_48dp", "ic_home_black_48dp", "ic_home_white_48dp", "ic_http_black_48dp", "ic_image_black_48dp", "ic_important_devices_black_48dp", "ic_important_devices_white_48dp", "ic_inbox_black_48dp", "ic_inbox_white_48dp", "ic_input_white_48dp", "ic_invert_colors_black_48dp", "ic_invert_colors_white_48dp", "ic_landscape_black_48dp", "ic_language_black_48dp", "ic_language_white_48dp"];
ui.icons.setDataSource(icons);
ui.icons.on("item_click", function(icon){
var d = "@drawabe/" + icon;
setClip(d);
toast(d + "已复制到剪贴板");
});

View File

@ -8,11 +8,23 @@ module.exports = function (runtime, global) {
ui.__view_cache__ = {};
ui.layout = function (xml) {
if(!activity){
throw new Error("需要在ui模式下运行才能使用该函数");
}
runtime.ui.layoutInflater.setContext(activity);
var view = runtime.ui.layoutInflater.inflate(xml.toString());
ui.setContentView(view);
}
ui.inflate = function(xml, parent){
if(!activity){
throw new Error("需要在ui模式下运行才能使用该函数");
}
parent = parent || null;
runtime.ui.layoutInflater.setContext(activity);
return decorate(runtime.ui.layoutInflater.inflate(xml.toString(), parent));
}
ui.setContentView = function (view) {
ui.view = view;
ui.__view_cache__ = {};
@ -86,7 +98,8 @@ module.exports = function (runtime, global) {
}
runtime.ui.bindingContext = global;
runtime.ui.layoutInflater.setLayoutInflaterDelegate({
var layoutInflater = runtime.ui.layoutInflater;
layoutInflater.setLayoutInflaterDelegate({
beforeConvertXml: function (xml) {
return null;
},
@ -109,7 +122,8 @@ module.exports = function (runtime, global) {
return null;
},
afterCreateView: function (view, node, viewName, attrs) {
if (view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsListView") {
if (view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsListView" ||
view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsGridView") {
initListView(view);
}
return view;
@ -133,6 +147,11 @@ module.exports = function (runtime, global) {
return false;
},
beforeApplyAttribute: function (inflater, view, ns, attrName, value, parent, attrs) {
var isDynamic = layoutInflater.isDynamicValue(value);
if ((isDynamic && layoutInflater.getInflateFlags() == layoutInflater.FLAG_IGNORES_DYNAMIC_ATTRS)
|| (!isDynamic && layoutInflater.getInflateFlags() == layoutInflater.FLAG_JUST_DYNAMIC_ATTRS)) {
return true;
}
value = bind(value);
inflater.setAttr(view, ns, attrName, value, parent, attrs);
this.afterApplyAttribute(inflater, view, ns, attrName, value, parent, attrs);
@ -171,7 +190,8 @@ module.exports = function (runtime, global) {
function decorate(view) {
var view = global.events.__asEmitter__(Object.create(view));
if (view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsListView") {
if (view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsListView"
|| view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsGridView") {
view = decorateList(view);
}
var gestureDetector = new android.view.GestureDetector(context, {

View File

@ -50,6 +50,11 @@ import javax.xml.parsers.DocumentBuilderFactory;
public class DynamicLayoutInflater {
public static final int FLAG_DEFAULT = 0;
public static final int FLAG_IGNORES_DYNAMIC_ATTRS = 1;
public static final int FLAG_JUST_DYNAMIC_ATTRS = 2;
private static final String LOG_TAG = "DynamicLayoutInflater";
private Map<String, ViewInflater<?>> mViewAttrSetters = new HashMap<>();
@ -58,6 +63,7 @@ public class DynamicLayoutInflater {
private ResourceParser mResourceParser;
@NonNull
private LayoutInflaterDelegate mLayoutInflaterDelegate = LayoutInflaterDelegate.NO_OP;
private int mInflateFlags;
public DynamicLayoutInflater(ResourceParser resourceParser) {
mResourceParser = resourceParser;
@ -72,6 +78,14 @@ public class DynamicLayoutInflater {
this.mViewCreators = new HashMap<>(inflater.mViewCreators);
}
public int getInflateFlags() {
return mInflateFlags;
}
public void setInflateFlags(int inflateFlags) {
mInflateFlags = inflateFlags;
}
public ResourceParser getResourceParser() {
return mResourceParser;
}
@ -160,8 +174,11 @@ public class DynamicLayoutInflater {
return view;
HashMap<String, String> attrs = getAttributesMap(node);
view = doCreateView(node, node.getNodeName(), attrs);
if (parent != null && attachToParent) {
parent.addView(view); // have to add to parent to enable certain layout attrs
if (parent != null) {
parent.addView(view); // have to add to parent to generate layout params
if (!attachToParent) {
parent.removeView(view);
}
}
ViewInflater<View> inflater = applyAttributes(view, attrs, parent);
if (!(view instanceof ViewGroup) || !node.hasChildNodes()) {
@ -297,10 +314,22 @@ public class DynamicLayoutInflater {
if (mLayoutInflaterDelegate.beforeApplyAttribute(inflater, view, ns, attrName, value, parent, attrs)) {
return;
}
boolean isDynamic = isDynamicValue(value);
if ((isDynamic && mInflateFlags == FLAG_IGNORES_DYNAMIC_ATTRS)
|| (!isDynamic && mInflateFlags == FLAG_JUST_DYNAMIC_ATTRS)) {
return;
}
inflater.setAttr(view, ns, attrName, value, parent, attrs);
mLayoutInflaterDelegate.afterApplyAttribute(inflater, view, ns, attrName, value, parent, attrs);
}
public boolean isDynamicValue(String value) {
int i = value.indexOf("{{");
if (i < 0)
return false;
return value.indexOf("}}", i + 1) >= 0;
}
}

View File

@ -25,5 +25,5 @@ public interface ViewInflater<V extends View> {
boolean inflateChildren(DynamicLayoutInflater inflater, Node node, V parent);
@Nullable
ViewCreator<V> getCreator();
ViewCreator<? super V> getCreator();
}

View File

@ -616,7 +616,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
@Nullable
@Override
public ViewCreator<V> getCreator() {
public ViewCreator<? super V> getCreator() {
return null;
}
}

View File

@ -0,0 +1,45 @@
package com.stardust.autojs.core.ui.inflater.inflaters;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.view.ViewGroup;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.ViewCreator;
import com.stardust.autojs.core.ui.widget.JsGridView;
import com.stardust.autojs.core.ui.widget.JsListView;
import com.stardust.autojs.runtime.ScriptRuntime;
import java.util.Map;
/**
* Created by Stardust on 2018/3/30.
*/
public class JsGridViewInflater<V extends JsGridView> extends JsListViewInflater<V> {
public JsGridViewInflater(ResourceParser resourceParser, ScriptRuntime runtime) {
super(resourceParser, runtime);
}
@Override
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
switch (attr) {
case "orientation":
((GridLayoutManager) view.getLayoutManager()).setOrientation(LinearLayoutInflater.ORIENTATIONS.get(value));
return true;
case "spanCount":
((GridLayoutManager) view.getLayoutManager()).setSpanCount(Integer.parseInt(value));
return true;
default:
return super.setAttr(view, attr, value, parent, attrs);
}
}
@Nullable
@Override
public ViewCreator<? super JsListView> getCreator() {
return (context, attrs) -> new JsGridView(context, getRuntime());
}
}

View File

@ -21,17 +21,21 @@ import java.util.Map;
* Created by Stardust on 2018/3/28.
*/
public class JsListViewInflater extends BaseViewInflater<JsListView> {
public class JsListViewInflater<V extends JsListView> extends BaseViewInflater<V> {
private ScriptRuntime mRuntime;
private final ScriptRuntime mRuntime;
public JsListViewInflater(ResourceParser resourceParser, ScriptRuntime runtime) {
super(resourceParser);
mRuntime = runtime;
}
public ScriptRuntime getRuntime() {
return mRuntime;
}
@Override
public boolean setAttr(JsListView view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
switch (attr) {
case "orientation":
view.setLayoutManager(new WrapContentLinearLayoutManager(view.getContext(), LinearLayoutInflater.ORIENTATIONS.get(value), false));
@ -42,7 +46,7 @@ public class JsListViewInflater extends BaseViewInflater<JsListView> {
}
@Override
public boolean setAttr(JsListView view, String ns, String attrName, String value, ViewGroup parent, Map<String, String> attrs) {
public boolean setAttr(V view, String ns, String attrName, String value, ViewGroup parent, Map<String, String> attrs) {
return super.setAttr(view, ns, attrName, value, parent, attrs);
}
@ -60,7 +64,7 @@ public class JsListViewInflater extends BaseViewInflater<JsListView> {
@Nullable
@Override
public ViewCreator<JsListView> getCreator() {
public ViewCreator<? super JsListView> getCreator() {
return (context, attrs) -> new JsListView(context, mRuntime);
}
}

View File

@ -55,8 +55,11 @@ public class Drawables {
}
public Drawable loadDrawableResources(Context context, String value) {
return context.getResources().getDrawable(context.getResources().getIdentifier(value, "drawable",
context.getPackageName()));
int resId = context.getResources().getIdentifier(value, "drawable",
context.getPackageName());
if (resId == 0)
throw new Resources.NotFoundException("drawable not found: " + value);
return context.getResources().getDrawable(resId);
}
public Drawable loadAttrResources(Context context, String value) {

View File

@ -0,0 +1,23 @@
package com.stardust.autojs.core.ui.widget;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import com.stardust.autojs.runtime.ScriptRuntime;
/**
* Created by Stardust on 2018/3/30.
*/
public class JsGridView extends JsListView {
public JsGridView(Context context, ScriptRuntime scriptRuntime) {
super(context, scriptRuntime);
}
@Override
protected void init() {
super.init();
setLayoutManager(new GridLayoutManager(getContext(), 1));
}
}

View File

@ -1,6 +1,7 @@
package com.stardust.autojs.core.ui.widget;
import android.content.Context;
import android.os.Handler;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
@ -47,11 +48,12 @@ public class JsListView extends RecyclerView {
init();
}
private void init() {
protected void init() {
setAdapter(new Adapter());
setLayoutManager(new WrapContentLinearLayoutManager(getContext()));
}
public void setOnItemTouchListener(OnItemTouchListener onItemTouchListener) {
mOnItemTouchListener = onItemTouchListener;
}
@ -101,10 +103,13 @@ public class JsListView extends RecyclerView {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
try {
mDynamicLayoutInflater.setInflateFlags(DynamicLayoutInflater.FLAG_IGNORES_DYNAMIC_ATTRS);
return new ViewHolder(mDynamicLayoutInflater.inflate(mItemTemplate, parent, false));
} catch (Exception e) {
mScriptRuntime.exit(e);
return new ViewHolder(new View(parent.getContext()));
} finally {
mDynamicLayoutInflater.setInflateFlags(DynamicLayoutInflater.FLAG_DEFAULT);
}
}
@ -113,10 +118,13 @@ public class JsListView extends RecyclerView {
try {
Object oldCtx = mScriptRuntime.ui.getBindingContext();
mScriptRuntime.ui.setBindingContext(mDataSourceAdapter.getItem(mDataSource, position));
applyDynamicAttrs(mItemTemplate, holder.itemView, (ViewGroup) holder.itemView.getParent());
mDynamicLayoutInflater.setInflateFlags(DynamicLayoutInflater.FLAG_JUST_DYNAMIC_ATTRS);
applyDynamicAttrs(mItemTemplate, holder.itemView, JsListView.this);
mScriptRuntime.ui.setBindingContext(oldCtx);
} catch (Exception e) {
mScriptRuntime.exit(e);
} finally {
mDynamicLayoutInflater.setInflateFlags(DynamicLayoutInflater.FLAG_DEFAULT);
}
}

View File

@ -17,6 +17,7 @@ import com.stardust.autojs.core.graphics.ScriptCanvasView;
import com.stardust.autojs.core.ui.widget.JsButton;
import com.stardust.autojs.core.ui.widget.JsEditText;
import com.stardust.autojs.core.ui.widget.JsFrameLayout;
import com.stardust.autojs.core.ui.widget.JsGridView;
import com.stardust.autojs.core.ui.widget.JsImageView;
import com.stardust.autojs.core.ui.widget.JsLinearLayout;
import com.stardust.autojs.core.ui.widget.JsListView;
@ -69,6 +70,7 @@ public class XmlConverter {
.map("toolbar", Toolbar.class.getName())
.map("canvas", ScriptCanvasView.class.getName())
.map("list", JsListView.class.getName())
.map("grid", JsGridView.class.getName())
);
private static final AttributeHandler ATTRIBUTE_HANDLER = new AttributeHandler.AttrNameRouter()

View File

@ -65,8 +65,9 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
public void forceStop() {
LooperHelper.quitForThread(getThread());
Activity activity = (Activity) getTag("activity");
if (activity != null)
if (activity != null) {
activity.finish();
}
super.forceStop();
}

View File

@ -7,8 +7,10 @@ import com.stardust.autojs.core.graphics.ScriptCanvasView;
import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.inflaters.CanvasViewInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.JsGridViewInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.JsImageViewInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.JsListViewInflater;
import com.stardust.autojs.core.ui.widget.JsGridView;
import com.stardust.autojs.core.ui.widget.JsImageView;
import com.stardust.autojs.core.ui.widget.JsListView;
import com.stardust.autojs.rhino.ProxyObject;
@ -43,6 +45,8 @@ public class UI extends ProxyObject {
new JsImageViewInflater(mResourceParser));
mDynamicLayoutInflater.registerViewAttrSetter(JsListView.class.getName(),
new JsListViewInflater(mResourceParser, runtime));
mDynamicLayoutInflater.registerViewAttrSetter(JsGridView.class.getName(),
new JsGridViewInflater(mResourceParser, runtime));
mDynamicLayoutInflater.registerViewAttrSetter(ScriptCanvasView.class.getName(),
new CanvasViewInflater(mResourceParser, runtime));
mProperties.put("layoutInflater", this.mDynamicLayoutInflater);