fix text node shadow & gradient conflict
This commit is contained in:
		| @@ -0,0 +1,174 @@ | ||||
| package pub.doric.shader; | ||||
|  | ||||
| import android.annotation.SuppressLint; | ||||
| import android.content.Context; | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.LinearGradient; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.graphics.Shader; | ||||
| import android.text.Layout; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import androidx.annotation.Nullable; | ||||
|  | ||||
| @SuppressLint("AppCompatCustomView") | ||||
| public class DoricTextView extends TextView { | ||||
|  | ||||
|     private boolean strikethrough = false; | ||||
|     private boolean underline = false; | ||||
|  | ||||
|     private float shadowAlpha = 0; | ||||
|     private float shadowRadius = 0; | ||||
|     private float shadowDx = 0; | ||||
|     private float shadowDy = 0; | ||||
|     private int shadowColor = Color.TRANSPARENT; | ||||
|  | ||||
|     private float gradientAngle = 0; | ||||
|     private int[] gradientColors = null; | ||||
|     private float[] gradientPositions = null; | ||||
|  | ||||
|     public DoricTextView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public DoricTextView(Context context, @Nullable AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
|  | ||||
|     public DoricTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     public void setShadow(float alpha, float radius, float dx, float dy, int color) { | ||||
|         this.shadowAlpha = alpha; | ||||
|         this.shadowRadius = radius; | ||||
|         this.shadowDx = dx; | ||||
|         this.shadowDy = dy; | ||||
|         this.shadowColor = color; | ||||
|  | ||||
|         getPaint().setAlpha((int) (255 * alpha)); | ||||
|         getPaint().setShadowLayer(radius, dx, dy, color); | ||||
|     } | ||||
|  | ||||
|     public boolean hasShadow() { | ||||
|         return this.shadowAlpha > 0; | ||||
|     } | ||||
|  | ||||
|     public void setGradient(float angle, int[] colors, float[] positions) { | ||||
|         this.gradientAngle = angle; | ||||
|         this.gradientColors = colors; | ||||
|         this.gradientPositions = positions; | ||||
|  | ||||
|         invalidate(); | ||||
|     } | ||||
|  | ||||
|     public boolean hasGradient() { | ||||
|         return this.gradientColors != null; | ||||
|     } | ||||
|  | ||||
|     public void setUnderline(boolean underline) { | ||||
|         this.underline = underline; | ||||
|         getPaint().setUnderlineText(underline); | ||||
|     } | ||||
|  | ||||
|     public void setStrikethrough(boolean strikethrough) { | ||||
|         this.strikethrough = strikethrough; | ||||
|         getPaint().setStrikeThruText(strikethrough); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDraw(Canvas canvas) { | ||||
|  | ||||
|         if (hasGradient()) { | ||||
|             if (hasShadow() || strikethrough || underline) { | ||||
|                 getPaint().setShader(null); | ||||
|  | ||||
|                 // draw the shadow | ||||
|                 if (hasShadow()) { | ||||
|                     // shadowColor must be opaque. | ||||
|                     setTextColor(0x00ffffff); | ||||
|                     getPaint().setAlpha((int) (255 * shadowAlpha)); | ||||
|                     getPaint().setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); | ||||
|                 } | ||||
|                 getPaint().setStrikeThruText(strikethrough); | ||||
|                 getPaint().setUnderlineText(underline); | ||||
|  | ||||
|                 super.onDraw(canvas); | ||||
|             } | ||||
|  | ||||
|             // draw the gradient filled text | ||||
|             if (hasShadow()) { | ||||
|                 getPaint().clearShadowLayer(); | ||||
|             } | ||||
|  | ||||
|             // gradient colors must be opaque, too. | ||||
|             setGradientTextColor(this, this.gradientAngle, this.gradientColors, this.gradientPositions); | ||||
|             super.onDraw(canvas); | ||||
|         } else { | ||||
|             super.onDraw(canvas); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void setGradientTextColor(final TextView textView, final float angle, final int[] colors, final float[] positions) { | ||||
|         final Rect textBound = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); | ||||
|  | ||||
|         final Layout layout = textView.getLayout(); | ||||
|  | ||||
|         if (layout == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < textView.getLineCount(); i++) { | ||||
|             float left = layout.getLineLeft(i); | ||||
|             float right = layout.getLineRight(i); | ||||
|             if (left < textBound.left) textBound.left = (int) left; | ||||
|             if (right > textBound.right) textBound.right = (int) right; | ||||
|         } | ||||
|         textBound.top = layout.getLineTop(0); | ||||
|         textBound.bottom = layout.getLineBottom(textView.getLineCount() - 1); | ||||
|         if (textView.getIncludeFontPadding()) { | ||||
|             Paint.FontMetrics fontMetrics = textView.getPaint().getFontMetrics(); | ||||
|             textBound.top += (fontMetrics.ascent - fontMetrics.top); | ||||
|             textBound.bottom -= (fontMetrics.bottom - fontMetrics.descent); | ||||
|         } | ||||
|  | ||||
|         double angleInRadians = Math.toRadians(angle); | ||||
|  | ||||
|         double r = Math.sqrt(Math.pow(textBound.bottom - textBound.top, 2) + | ||||
|                 Math.pow(textBound.right - textBound.left, 2)) / 2; | ||||
|  | ||||
|         float centerX = textBound.left + (textBound.right - textBound.left) / 2.f; | ||||
|         float centerY = textBound.top + (textBound.bottom - textBound.top) / 2.f; | ||||
|  | ||||
|         float startX = (float) (centerX - r * Math.cos(angleInRadians)); | ||||
|         float startY = (float) (centerY + r * Math.sin(angleInRadians)); | ||||
|  | ||||
|         float endX = (float) (centerX + r * Math.cos(angleInRadians)); | ||||
|         float endY = (float) (centerY - r * Math.sin(angleInRadians)); | ||||
|  | ||||
|         Shader textShader = new LinearGradient(startX, startY, endX, endY, colors, positions, | ||||
|                 Shader.TileMode.CLAMP); | ||||
|  | ||||
|         textView.setTextColor(0xffffffff); | ||||
|         textView.getPaint().setShader(textShader); | ||||
|     } | ||||
|  | ||||
|     public void reset() { | ||||
|         strikethrough = false; | ||||
|         underline = false; | ||||
|  | ||||
|         shadowAlpha = 0; | ||||
|         shadowRadius = 0; | ||||
|         shadowDx = 0; | ||||
|         shadowDy = 0; | ||||
|         shadowColor = Color.TRANSPARENT; | ||||
|  | ||||
|         gradientAngle = 0; | ||||
|         gradientColors = null; | ||||
|         gradientPositions = null; | ||||
|         invalidate(); | ||||
|     } | ||||
| } | ||||
| @@ -16,20 +16,14 @@ | ||||
| package pub.doric.shader; | ||||
|  | ||||
| import android.graphics.Color; | ||||
| import android.graphics.LinearGradient; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.graphics.Shader; | ||||
| import android.graphics.Typeface; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.text.Html; | ||||
| import android.text.Layout; | ||||
| import android.text.Spanned; | ||||
| import android.text.TextUtils; | ||||
| import android.util.TypedValue; | ||||
| import android.view.Gravity; | ||||
| import android.view.ViewTreeObserver; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import androidx.core.content.res.ResourcesCompat; | ||||
|  | ||||
| @@ -60,14 +54,14 @@ import pub.doric.utils.ThreadMode; | ||||
|  * @CreateDate: 2019-07-20 | ||||
|  */ | ||||
| @DoricPlugin(name = "Text") | ||||
| public class TextNode extends ViewNode<TextView> { | ||||
| public class TextNode extends ViewNode<DoricTextView> { | ||||
|     public TextNode(DoricContext doricContext) { | ||||
|         super(doricContext); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected TextView build() { | ||||
|         TextView tv = new TextView(getContext()); | ||||
|     protected DoricTextView build() { | ||||
|         DoricTextView tv = new DoricTextView(getContext()); | ||||
|         tv.setGravity(Gravity.CENTER); | ||||
|         tv.setMaxLines(1); | ||||
|         tv.setSingleLine(true); | ||||
| @@ -90,7 +84,7 @@ public class TextNode extends ViewNode<TextView> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void blend(final TextView view, final String name, final JSValue prop) { | ||||
|     protected void blend(final DoricTextView view, final String name, final JSValue prop) { | ||||
|         switch (name) { | ||||
|             case "text": | ||||
|                 if (!prop.isString()) { | ||||
| @@ -178,7 +172,7 @@ public class TextNode extends ViewNode<TextView> { | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
|                             setGradientTextColor(view, angle, colors, locations); | ||||
|                             mView.setGradient(angle, colors, locations); | ||||
|  | ||||
|                             return true; | ||||
|                         } | ||||
| @@ -312,40 +306,40 @@ public class TextNode extends ViewNode<TextView> { | ||||
|                 break; | ||||
|             case "strikethrough": | ||||
|                 if (prop.isBoolean()) { | ||||
|                     view.getPaint().setStrikeThruText(prop.asBoolean().value()); | ||||
|                     view.setStrikethrough(prop.asBoolean().value()); | ||||
|                 } | ||||
|                 break; | ||||
|             case "underline": | ||||
|                 if (prop.isBoolean()) { | ||||
|                     view.getPaint().setUnderlineText(prop.asBoolean().value()); | ||||
|                     view.setUnderline(prop.asBoolean().value()); | ||||
|                 } | ||||
|                 break; | ||||
|             case "htmlText": | ||||
|                 if (prop.isString()) { | ||||
|                     getDoricContext().getDriver().asyncCall(new Callable<Spanned>() { | ||||
|                         @Override | ||||
|                         public Spanned call() { | ||||
|                             return HtmlParser.buildSpannedText(prop.asString().value(), | ||||
|                                     new Html.ImageGetter() { | ||||
|                                         @Override | ||||
|                                         public Drawable getDrawable(String source) { | ||||
|                                             try { | ||||
|                                                 Drawable drawable = Glide.with(view) | ||||
|                                                         .asDrawable() | ||||
|                                                         .load(source) | ||||
|                                                         .submit() | ||||
|                                                         .get(); | ||||
|                                                 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); | ||||
|                                                 return drawable; | ||||
|                                             } catch (Exception e) { | ||||
|                                                 e.printStackTrace(); | ||||
|                                             } | ||||
|                                             return null; | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     new CustomTagHandler()); | ||||
|                         } | ||||
|                     }, ThreadMode.INDEPENDENT) | ||||
|                                 @Override | ||||
|                                 public Spanned call() { | ||||
|                                     return HtmlParser.buildSpannedText(prop.asString().value(), | ||||
|                                             new Html.ImageGetter() { | ||||
|                                                 @Override | ||||
|                                                 public Drawable getDrawable(String source) { | ||||
|                                                     try { | ||||
|                                                         Drawable drawable = Glide.with(view) | ||||
|                                                                 .asDrawable() | ||||
|                                                                 .load(source) | ||||
|                                                                 .submit() | ||||
|                                                                 .get(); | ||||
|                                                         drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); | ||||
|                                                         return drawable; | ||||
|                                                     } catch (Exception e) { | ||||
|                                                         e.printStackTrace(); | ||||
|                                                     } | ||||
|                                                     return null; | ||||
|                                                 } | ||||
|                                             }, | ||||
|                                             new CustomTagHandler()); | ||||
|                                 } | ||||
|                             }, ThreadMode.INDEPENDENT) | ||||
|                             .setCallback(new AsyncResult.Callback<Spanned>() { | ||||
|                                 @Override | ||||
|                                 public void onResult(final Spanned result) { | ||||
| @@ -389,8 +383,8 @@ public class TextNode extends ViewNode<TextView> { | ||||
|                 break; | ||||
|             case "shadow": | ||||
|                 if (prop.isObject()) { | ||||
|                     mView.setAlpha((prop.asObject().getProperty("opacity").asNumber().toFloat())); | ||||
|                     mView.setShadowLayer( | ||||
|                     mView.setShadow( | ||||
|                             prop.asObject().getProperty("opacity").asNumber().toFloat(), | ||||
|                             prop.asObject().getProperty("radius").asNumber().toFloat(), | ||||
|                             DoricUtils.dp2px(prop.asObject().getProperty("offsetX").asNumber().toFloat()), | ||||
|                             DoricUtils.dp2px(prop.asObject().getProperty("offsetY").asNumber().toFloat()), | ||||
| @@ -404,57 +398,13 @@ public class TextNode extends ViewNode<TextView> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void setGradientTextColor(final TextView textView, final float angle, final int[] colors, final float[] positions) { | ||||
|         final Rect textBound = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); | ||||
|  | ||||
|         final Layout layout = textView.getLayout(); | ||||
|  | ||||
|         if (layout == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < textView.getLineCount(); i++) { | ||||
|             float left = layout.getLineLeft(i); | ||||
|             float right = layout.getLineRight(i); | ||||
|             if (left < textBound.left) textBound.left = (int) left; | ||||
|             if (right > textBound.right) textBound.right = (int) right; | ||||
|         } | ||||
|         textBound.top = layout.getLineTop(0); | ||||
|         textBound.bottom = layout.getLineBottom(textView.getLineCount() - 1); | ||||
|         if (textView.getIncludeFontPadding()) { | ||||
|             Paint.FontMetrics fontMetrics = textView.getPaint().getFontMetrics(); | ||||
|             textBound.top += (fontMetrics.ascent - fontMetrics.top); | ||||
|             textBound.bottom -= (fontMetrics.bottom - fontMetrics.descent); | ||||
|         } | ||||
|  | ||||
|         double angleInRadians = Math.toRadians(angle); | ||||
|  | ||||
|         double r = Math.sqrt(Math.pow(textBound.bottom - textBound.top, 2) + | ||||
|                 Math.pow(textBound.right - textBound.left, 2)) / 2; | ||||
|  | ||||
|         float centerX = textBound.left + (textBound.right - textBound.left) / 2.f; | ||||
|         float centerY = textBound.top + (textBound.bottom - textBound.top) / 2.f; | ||||
|  | ||||
|         float startX = (float) (centerX - r * Math.cos(angleInRadians)); | ||||
|         float startY = (float) (centerY + r * Math.sin(angleInRadians)); | ||||
|  | ||||
|         float endX = (float) (centerX + r * Math.cos(angleInRadians)); | ||||
|         float endY = (float) (centerY - r * Math.sin(angleInRadians)); | ||||
|  | ||||
|         Shader textShader = new LinearGradient(startX, startY, endX, endY, colors, positions, | ||||
|                 Shader.TileMode.CLAMP); | ||||
|  | ||||
|         textView.setTextColor(Color.WHITE); | ||||
|         textView.getPaint().setShader(textShader); | ||||
|         textView.invalidate(); | ||||
|     } | ||||
|  | ||||
|     private static File createFile(byte[] bfile, String filePath,String fileName) throws IOException { | ||||
|     private static File createFile(byte[] bfile, String filePath, String fileName) throws IOException { | ||||
|         BufferedOutputStream bos = null; | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             File dir = new File(filePath); | ||||
|             if(!dir.exists()){ | ||||
|             if (!dir.exists()) { | ||||
|                 dir.mkdirs(); | ||||
|             } | ||||
|             String pathName = filePath + File.separator + fileName; | ||||
| @@ -496,7 +446,5 @@ public class TextNode extends ViewNode<TextView> { | ||||
|         mView.setMaxLines(1); | ||||
|         mView.setSingleLine(true); | ||||
|         mView.setEllipsize(TextUtils.TruncateAt.END); | ||||
|         mView.getPaint().setStrikeThruText(false); | ||||
|         mView.getPaint().setUnderlineText(false); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user