Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

Commit

Permalink
* [android] Support richtext component (#1796)
Browse files Browse the repository at this point in the history
  • Loading branch information
miomin authored and YorkShen committed Nov 23, 2018
1 parent bdd5337 commit 12e605f
Show file tree
Hide file tree
Showing 16 changed files with 1,058 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* 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.alibaba.weex.commons.adapter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.Gravity;

import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.taobao.weex.WXSDKManager;
import com.taobao.weex.adapter.DrawableStrategy;
import com.taobao.weex.adapter.IDrawableLoader;

public class PicassoBasedDrawableLoader implements IDrawableLoader {

private Context mContext;

public PicassoBasedDrawableLoader(Context context) {
mContext = context;
}

@Override
public void setDrawable(final String url,
final DrawableTarget drawableTarget,
final DrawableStrategy drawableStrategy) {
WXSDKManager.getInstance().postOnUiThread(new Runnable() {
@Override
public void run() {
String temp = url;
if (url.startsWith("//")) {
temp = "http:" + url;
}

/** This is a hack for picasso, as Picasso hold weakReference to Target.
* http://stackoverflow.com/questions/24180805/onbitmaploaded-of-target-object-not-called-on-first-load
*/
class PlaceHolderDrawableTarget extends Drawable implements Target {

@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
bitmapDrawable.setGravity(Gravity.FILL);
drawableTarget.setDrawable(bitmapDrawable, true);
}

@Override
public void onBitmapFailed(Drawable errorDrawable) {

}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
drawableTarget.setDrawable(this, true);
}

@Override
public void draw(Canvas canvas) {

}

@Override
public void setAlpha(int alpha) {

}

@Override
public void setColorFilter(ColorFilter colorFilter) {

}

@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
Picasso.
with(mContext).
load(temp).
resize(drawableStrategy.width, drawableStrategy.height).
onlyScaleDown().
into(new PlaceHolderDrawableTarget());
}
}, 0);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.alibaba.weex.commons.adapter.DefaultWebSocketAdapterFactory;
import com.alibaba.weex.commons.adapter.ImageAdapter;
import com.alibaba.weex.commons.adapter.JSExceptionAdapter;
import com.alibaba.weex.commons.adapter.PicassoBasedDrawableLoader;
import com.alibaba.weex.extend.adapter.ApmGenerator;
import com.alibaba.weex.extend.adapter.DefaultAccessibilityRoleAdapter;
import com.alibaba.weex.extend.adapter.InterceptWXHttpAdapter;
Expand Down Expand Up @@ -72,6 +73,7 @@ public void onCreate() {
new InitConfig.Builder()
//.setImgAdapter(new FrescoImageAdapter())// use fresco adapter
.setImgAdapter(new ImageAdapter())
.setDrawableLoader(new PicassoBasedDrawableLoader(getApplicationContext()))
.setWebSocketAdapterFactory(new DefaultWebSocketAdapterFactory())
.setJSExceptionAdapter(new JSExceptionAdapter())
.setHttpAdapter(new InterceptWXHttpAdapter())
Expand All @@ -86,7 +88,6 @@ public void onCreate() {
WXSDKEngine.registerComponent("synccomponent", WXComponentSyncTest.class);
WXSDKEngine.registerComponent(WXParallax.PARALLAX, WXParallax.class);

WXSDKEngine.registerComponent("richtext", RichText.class);
WXSDKEngine.registerModule("render", RenderModule.class);
WXSDKEngine.registerModule("event", WXEventModule.class);
WXSDKEngine.registerModule("syncTest", SyncTestModule.class);
Expand Down
11 changes: 11 additions & 0 deletions android/sdk/src/main/java/com/taobao/weex/WXSDKEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@
import com.taobao.weex.ui.component.WXText;
import com.taobao.weex.ui.component.WXVideo;
import com.taobao.weex.ui.component.WXWeb;
import com.taobao.weex.ui.component.basic.WXBasicComponent;
import com.taobao.weex.ui.component.list.HorizontalListComponent;
import com.taobao.weex.ui.component.list.SimpleListComponent;
import com.taobao.weex.ui.component.list.WXCell;
import com.taobao.weex.ui.component.list.WXListComponent;
import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
import com.taobao.weex.ui.component.richtext.WXRichText;
import com.taobao.weex.ui.config.AutoScanConfigRegister;
import com.taobao.weex.ui.module.WXLocaleModule;
import com.taobao.weex.ui.module.WXMetaModule;
Expand Down Expand Up @@ -330,6 +332,15 @@ private static void register() {
WXBasicComponentType.RECYCLER,
WXBasicComponentType.WATERFALL);

registerComponent(
new SimpleComponentHolder(
WXRichText.class,
new WXRichText.Creator()
),
false,
WXBasicComponentType.RICHTEXT
);

String simpleList = "simplelist";
registerComponent(SimpleListComponent.class,false,simpleList);
registerComponent(WXRecyclerTemplateList.class, false,WXBasicComponentType.RECYCLE_LIST);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
public interface IDrawableLoader {

interface DrawableTarget {

void setDrawable(@Nullable Drawable drawable, boolean resetBounds);
}

interface StaticTarget extends DrawableTarget{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class WXBasicComponentType {
public static final String LOADING = "loading";
public static final String LOADING_INDICATOR = "loading-indicator";
public static final String CYCLE_SLIDER = "cycleslider";
public static final String RICHTEXT = "richtext";

public static final String RECYCLE_LIST = "recycle-list";
public static final String CELL_SLOT = "cell-slot";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* 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.component.richtext;


import android.content.Context;
import android.support.annotation.NonNull;
import android.text.Spannable;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.TextUtils;

import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.layout.measurefunc.TextContentBoxMeasurement;
import com.taobao.weex.ui.ComponentCreator;
import com.taobao.weex.ui.action.BasicComponentData;
import com.taobao.weex.ui.component.WXComponent;
import com.taobao.weex.ui.component.WXText;
import com.taobao.weex.ui.component.WXVContainer;
import com.taobao.weex.ui.component.richtext.node.RichTextNode;

import java.lang.reflect.InvocationTargetException;

public class WXRichText extends WXText {

static class RichTextContentBoxMeasurement extends TextContentBoxMeasurement {

public RichTextContentBoxMeasurement(WXComponent component) {
super(component);
}

@NonNull
@Override
protected Spanned createSpanned(String text) {
if (mComponent.getInstance() != null & mComponent.getInstance().getUIContext() != null &&
!TextUtils.isEmpty(mComponent.getInstanceId())) {
Spannable spannable = RichTextNode.parse(
mComponent.getInstance().getUIContext(),
mComponent.getInstanceId(),
mComponent.getRef(),
text);
updateSpannable(spannable, RichTextNode.createSpanFlag(0));
return spannable;
} else {
return new SpannedString("");
}
}
}

public static class Creator implements ComponentCreator {

public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException {
return new WXRichText(instance, parent, basicComponentData);
}
}

public WXRichText(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) {
super(instance, parent, basicComponentData);
setContentBoxMeasurement(new RichTextContentBoxMeasurement(this));
}

@Override
protected WXRichTextView initComponentHostView(@NonNull Context context) {
return new WXRichTextView(context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* 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.component.richtext;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.widget.TextView;

import com.taobao.weex.ui.component.richtext.span.ImgSpan;
import com.taobao.weex.ui.view.WXTextView;

public class WXRichTextView extends WXTextView {

public WXRichTextView(Context context) {
super(context);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
boolean superResult = super.onTouchEvent(event);
boolean handled = false;
if (isEnabled() && getTextLayout() != null && getText() instanceof Spannable) {
Spannable spannable = (Spannable) getText();
handled = updateSelection(event, spannable);
}
return handled || superResult;
}

@Override
protected boolean verifyDrawable(Drawable who) {
super.verifyDrawable(who);
return true;
}

@Override
public void setTextLayout(Layout layout) {
super.setTextLayout(layout);
if (layout.getText() instanceof Spanned) {
Spanned spanned = (Spanned) layout.getText();
ImgSpan[] imgSpan = spanned.getSpans(0, spanned.length(), ImgSpan.class);
if (imgSpan != null) {
for (ImgSpan span : imgSpan) {
span.setView(this);
}
}
}
}

/**
* Mostly copied from
* {@link android.text.method.LinkMovementMethod#onTouchEvent(TextView, Spannable, MotionEvent)}.
*/
private boolean updateSelection(MotionEvent event, Spannable buffer) {
int action = event.getActionMasked();

if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();

x -= getPaddingLeft();
y -= getPaddingTop();

x += getScrollX();
y += getScrollY();

Layout layout = getTextLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);

ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(this);
} else {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}

return true;
} else {
Selection.removeSelection(buffer);
}
}

return false;
}


}
Loading

0 comments on commit 12e605f

Please sign in to comment.