mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Exposed properties to allow image to be cropped when there is border radius
This commit is contained in:
@@ -4,122 +4,165 @@
|
|||||||
package org.nativescript.widgets;
|
package org.nativescript.widgets;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.*;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hhristov
|
* @author hhristov
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ImageView extends android.widget.ImageView {
|
public class ImageView extends android.widget.ImageView {
|
||||||
|
private float cornerRadius = 0;
|
||||||
|
private float borderWidth = 0;
|
||||||
|
|
||||||
private double scaleW = 1;
|
private Path path = new Path();
|
||||||
private double scaleH = 1;
|
private RectF rect = new RectF();
|
||||||
|
|
||||||
public ImageView(Context context) {
|
|
||||||
super(context);
|
|
||||||
this.setScaleType(ScaleType.FIT_CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
|
|
||||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
private double scaleW = 1;
|
||||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
private double scaleH = 1;
|
||||||
|
|
||||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
public ImageView(Context context) {
|
||||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
super(context);
|
||||||
|
this.setScaleType(ScaleType.FIT_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getCornerRadius() {
|
||||||
|
return this.cornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCornerRadius(float radius) {
|
||||||
|
if (radius != this.cornerRadius) {
|
||||||
|
this.cornerRadius = radius;
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBorderWidth() {
|
||||||
|
return this.borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBorderWidth(float radius) {
|
||||||
|
if (radius != this.borderWidth) {
|
||||||
|
this.borderWidth = radius;
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
|
||||||
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||||
|
|
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||||
|
|
||||||
Drawable drawable = this.getDrawable();
|
Drawable drawable = this.getDrawable();
|
||||||
int measureWidth;
|
int measureWidth;
|
||||||
int measureHeight;
|
int measureHeight;
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
measureWidth = drawable.getIntrinsicWidth();
|
measureWidth = drawable.getIntrinsicWidth();
|
||||||
measureHeight = drawable.getIntrinsicHeight();
|
measureHeight = drawable.getIntrinsicHeight();
|
||||||
|
} else {
|
||||||
|
measureWidth = 0;
|
||||||
|
measureHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean finiteWidth = widthMode != MeasureSpec.UNSPECIFIED;
|
||||||
|
boolean finiteHeight = heightMode != MeasureSpec.UNSPECIFIED;
|
||||||
|
|
||||||
|
if (measureWidth != 0 && measureHeight != 0 && (finiteWidth || finiteHeight)) {
|
||||||
|
this.computeScaleFactor(width, height, finiteWidth, finiteHeight, measureWidth, measureHeight);
|
||||||
|
int resultW = (int) Math.floor(measureWidth * this.scaleW);
|
||||||
|
int resultH = (int) Math.floor(measureHeight * this.scaleH);
|
||||||
|
|
||||||
|
measureWidth = finiteWidth ? Math.min(resultW, width) : resultW;
|
||||||
|
measureHeight = finiteHeight ? Math.min(resultH, height) : resultH;
|
||||||
|
}
|
||||||
|
|
||||||
|
measureWidth += this.getPaddingLeft() + this.getPaddingRight();
|
||||||
|
measureHeight += this.getPaddingTop() + this.getPaddingBottom();
|
||||||
|
|
||||||
|
measureWidth = Math.max(measureWidth, getSuggestedMinimumWidth());
|
||||||
|
measureHeight = Math.max(measureHeight, getSuggestedMinimumHeight());
|
||||||
|
|
||||||
|
if (CommonLayoutParams.debuggable > 0) {
|
||||||
|
StringBuilder sb = CommonLayoutParams.getStringBuilder();
|
||||||
|
sb.append("ImageView onMeasure: ");
|
||||||
|
sb.append(MeasureSpec.toString(widthMeasureSpec));
|
||||||
|
sb.append(", ");
|
||||||
|
sb.append(MeasureSpec.toString(heightMeasureSpec));
|
||||||
|
sb.append(", stretch: ");
|
||||||
|
sb.append(this.getScaleType());
|
||||||
|
sb.append(", measureWidth: ");
|
||||||
|
sb.append(measureWidth);
|
||||||
|
sb.append(", measureHeight: ");
|
||||||
|
sb.append(measureHeight);
|
||||||
|
|
||||||
|
CommonLayoutParams.log(CommonLayoutParams.tag, sb.toString());
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
measureWidth = 0;
|
|
||||||
measureHeight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean finiteWidth = widthMode != MeasureSpec.UNSPECIFIED;
|
|
||||||
boolean finiteHeight = heightMode != MeasureSpec.UNSPECIFIED;
|
|
||||||
|
|
||||||
if (measureWidth != 0 && measureHeight != 0 && (finiteWidth || finiteHeight)) {
|
|
||||||
this.computeScaleFactor(width, height, finiteWidth, finiteHeight, measureWidth, measureHeight);
|
|
||||||
int resultW = (int) Math.floor(measureWidth * this.scaleW);
|
|
||||||
int resultH = (int) Math.floor(measureHeight * this.scaleH);
|
|
||||||
|
|
||||||
measureWidth = finiteWidth ? Math.min(resultW, width) : resultW;
|
|
||||||
measureHeight = finiteHeight ? Math.min(resultH, height) : resultH;
|
|
||||||
}
|
|
||||||
|
|
||||||
measureWidth += this.getPaddingLeft() + this.getPaddingRight();
|
|
||||||
measureHeight += this.getPaddingTop() + this.getPaddingBottom();
|
|
||||||
|
|
||||||
measureWidth = Math.max(measureWidth, getSuggestedMinimumWidth());
|
|
||||||
measureHeight = Math.max(measureHeight, getSuggestedMinimumHeight());
|
|
||||||
|
|
||||||
if (CommonLayoutParams.debuggable > 0) {
|
|
||||||
StringBuilder sb = CommonLayoutParams.getStringBuilder();
|
|
||||||
sb.append("ImageView onMeasure: ");
|
|
||||||
sb.append(MeasureSpec.toString(widthMeasureSpec));
|
|
||||||
sb.append(", ");
|
|
||||||
sb.append(MeasureSpec.toString(heightMeasureSpec));
|
|
||||||
sb.append(", stretch: ");
|
|
||||||
sb.append(this.getScaleType());
|
|
||||||
sb.append(", measureWidth: ");
|
|
||||||
sb.append(measureWidth);
|
|
||||||
sb.append(", measureHeight: ");
|
|
||||||
sb.append(measureHeight);
|
|
||||||
|
|
||||||
CommonLayoutParams.log(CommonLayoutParams.tag, sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
int widthSizeAndState = resolveSizeAndState(measureWidth, widthMeasureSpec, 0);
|
int widthSizeAndState = resolveSizeAndState(measureWidth, widthMeasureSpec, 0);
|
||||||
int heightSizeAndState = resolveSizeAndState(measureHeight, heightMeasureSpec, 0);
|
int heightSizeAndState = resolveSizeAndState(measureHeight, heightMeasureSpec, 0);
|
||||||
|
|
||||||
this.setMeasuredDimension(widthSizeAndState, heightSizeAndState);
|
this.setMeasuredDimension(widthSizeAndState, heightSizeAndState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeScaleFactor(
|
private void computeScaleFactor(int measureWidth, int measureHeight, boolean widthIsFinite, boolean heightIsFinite, double nativeWidth, double nativeHeight) {
|
||||||
int measureWidth,
|
|
||||||
int measureHeight,
|
|
||||||
boolean widthIsFinite,
|
|
||||||
boolean heightIsFinite,
|
|
||||||
double nativeWidth,
|
|
||||||
double nativeHeight) {
|
|
||||||
|
|
||||||
this.scaleW = 1;
|
|
||||||
this.scaleH = 1;
|
|
||||||
|
|
||||||
ScaleType scale = this.getScaleType();
|
this.scaleW = 1;
|
||||||
|
this.scaleH = 1;
|
||||||
|
|
||||||
|
ScaleType scale = this.getScaleType();
|
||||||
if ((scale == ScaleType.CENTER_CROP || scale == ScaleType.FIT_CENTER || scale == ScaleType.FIT_XY) &&
|
if ((scale == ScaleType.CENTER_CROP || scale == ScaleType.FIT_CENTER || scale == ScaleType.FIT_XY) &&
|
||||||
(widthIsFinite || heightIsFinite)) {
|
(widthIsFinite || heightIsFinite)) {
|
||||||
|
|
||||||
this.scaleW = (nativeWidth > 0) ? measureWidth / nativeWidth : 0d;
|
this.scaleW = (nativeWidth > 0) ? measureWidth / nativeWidth : 0d;
|
||||||
this.scaleH = (nativeHeight > 0) ? measureHeight / nativeHeight : 0d;
|
this.scaleH = (nativeHeight > 0) ? measureHeight / nativeHeight : 0d;
|
||||||
|
|
||||||
if (!widthIsFinite) {
|
if (!widthIsFinite) {
|
||||||
this.scaleW = scaleH;
|
this.scaleW = scaleH;
|
||||||
}
|
} else if (!heightIsFinite) {
|
||||||
else if (!heightIsFinite) {
|
this.scaleH = scaleW;
|
||||||
this.scaleH = scaleW;
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No infinite dimensions.
|
// No infinite dimensions.
|
||||||
switch (scale) {
|
switch (scale) {
|
||||||
case FIT_CENTER:
|
case FIT_CENTER:
|
||||||
this.scaleH = this.scaleW < this.scaleH ? this.scaleW : this.scaleH;
|
this.scaleH = this.scaleW < this.scaleH ? this.scaleW : this.scaleH;
|
||||||
this.scaleW = this.scaleH;
|
this.scaleW = this.scaleH;
|
||||||
break;
|
break;
|
||||||
case CENTER_CROP:
|
case CENTER_CROP:
|
||||||
this.scaleH = this.scaleW > this.scaleH ? this.scaleW : this.scaleH;
|
this.scaleH = this.scaleW > this.scaleH ? this.scaleW : this.scaleH;
|
||||||
this.scaleW = this.scaleH;
|
this.scaleW = this.scaleH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
// floor the border width to avoid gaps between the border and the image
|
||||||
|
float roundedBorderWidth = (float) Math.floor(this.borderWidth);
|
||||||
|
float innerRadius = Math.max(0, this.cornerRadius - roundedBorderWidth);
|
||||||
|
|
||||||
|
// The border width is included in the padding so there is no need for
|
||||||
|
// clip if there is no inner border radius.
|
||||||
|
if (innerRadius != 0) {
|
||||||
|
this.rect.set(
|
||||||
|
roundedBorderWidth,
|
||||||
|
roundedBorderWidth,
|
||||||
|
this.getWidth() - roundedBorderWidth,
|
||||||
|
this.getHeight() - roundedBorderWidth);
|
||||||
|
|
||||||
|
this.path.reset();
|
||||||
|
this.path.addRoundRect(rect, innerRadius, innerRadius, android.graphics.Path.Direction.CW);
|
||||||
|
|
||||||
|
canvas.clipPath(this.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onDraw(canvas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user