记忆重椭圆渐变
Memory heavy oval gradient
如您所知,使用常规 Android API 无法绘制椭圆形径向渐变。
这就是我想要实现的:
所以我实现了这个解决方案:在方形位图上绘制一个规则的径向渐变,然后这个位图将被视图本身拉伸(想法在这里找到:)
这很好用,但是由于使用了 BitmapDrawable(请参阅下面的实施细节),此解决方案会占用大量内存。
欢迎提出任何关于如何避免使用如此大的位图的想法!
这是我的代码:
public class OvalGradientView extends ImageView {
private Drawable defaultBackgroundDrawable;
public OvalGradientView(Context context) {
super(context);
init();
}
public OvalGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public OvalGradientView(Context context, AttributeSet attrs, int defStyleAttr, Paint paint) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setScaleType(ScaleType.FIT_XY);
defaultBackgroundDrawable = getResources().getDrawable(R.drawable.default_background);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int width = getWidth();
int height = getHeight();
Rect currentBounds = defaultBackgroundDrawable.getBounds();
// check if we already have bitmap for these bounds
if (currentBounds.right == width && currentBounds.bottom == height) {
return;
}
// draw the drawable on square bitmap, it will be then stretched if needed to rectangular shape
// as the view gets more rectangular
defaultBackgroundDrawable.setBounds(0, 0, width, width);
Bitmap defaultBackgroundBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(defaultBackgroundBitmap);
defaultBackgroundDrawable.draw(canvas);
setImageBitmap(defaultBackgroundBitmap);
}
}
这是可绘制对象 XML - default_background
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#ffffff"
android:endColor="#ff6600"
android:gradientRadius="50%p"
android:type="radial" />
</shape
我不相信自己有能力创建那样的位图,尤其是全屏时。为什么不将 xml 形状也作为背景应用到 xml 中的容器视图?如果宽度和高度为 match_parent
,它将拉伸到视图的比例
public class OvalGradientView extends ImageView {
public OvalGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_sexy_gradient, this, true);
}
}
my_sexy_gradient.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/default_background"/>
我最终实现了这个:
public class MyBackgroundView extends ImageView {
public MyBackgroundView(Context context) {
super(context);
}
public MyBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
setBackgroundResource(R.drawable.my_background);
setScaleType(ScaleType.FIT_XY);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed) {
return;
}
int width = right - left;
int height = bottom - top;
float aspectRatio = (float) width / height;
if (aspectRatio > 1f) {
setScaleX(aspectRatio);
} else {
setScaleY(1 / aspectRatio);
}
}
}
其中 my_background 是:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/my_background_start_color"
android:endColor="@color/my_background_end_color"
android:gradientRadius="@fraction/my_background_gradient_radius_percent"
android:type="radial" />
</shape>
此视图的宽度和高度均为match_parent。
如您所知,使用常规 Android API 无法绘制椭圆形径向渐变。
这就是我想要实现的:
所以我实现了这个解决方案:在方形位图上绘制一个规则的径向渐变,然后这个位图将被视图本身拉伸(想法在这里找到:)
这很好用,但是由于使用了 BitmapDrawable(请参阅下面的实施细节),此解决方案会占用大量内存。
欢迎提出任何关于如何避免使用如此大的位图的想法!
这是我的代码:
public class OvalGradientView extends ImageView {
private Drawable defaultBackgroundDrawable;
public OvalGradientView(Context context) {
super(context);
init();
}
public OvalGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public OvalGradientView(Context context, AttributeSet attrs, int defStyleAttr, Paint paint) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setScaleType(ScaleType.FIT_XY);
defaultBackgroundDrawable = getResources().getDrawable(R.drawable.default_background);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int width = getWidth();
int height = getHeight();
Rect currentBounds = defaultBackgroundDrawable.getBounds();
// check if we already have bitmap for these bounds
if (currentBounds.right == width && currentBounds.bottom == height) {
return;
}
// draw the drawable on square bitmap, it will be then stretched if needed to rectangular shape
// as the view gets more rectangular
defaultBackgroundDrawable.setBounds(0, 0, width, width);
Bitmap defaultBackgroundBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(defaultBackgroundBitmap);
defaultBackgroundDrawable.draw(canvas);
setImageBitmap(defaultBackgroundBitmap);
}
}
这是可绘制对象 XML - default_background
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#ffffff"
android:endColor="#ff6600"
android:gradientRadius="50%p"
android:type="radial" />
</shape
我不相信自己有能力创建那样的位图,尤其是全屏时。为什么不将 xml 形状也作为背景应用到 xml 中的容器视图?如果宽度和高度为 match_parent
public class OvalGradientView extends ImageView {
public OvalGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_sexy_gradient, this, true);
}
}
my_sexy_gradient.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/default_background"/>
我最终实现了这个:
public class MyBackgroundView extends ImageView {
public MyBackgroundView(Context context) {
super(context);
}
public MyBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
setBackgroundResource(R.drawable.my_background);
setScaleType(ScaleType.FIT_XY);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!changed) {
return;
}
int width = right - left;
int height = bottom - top;
float aspectRatio = (float) width / height;
if (aspectRatio > 1f) {
setScaleX(aspectRatio);
} else {
setScaleY(1 / aspectRatio);
}
}
}
其中 my_background 是:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/my_background_start_color"
android:endColor="@color/my_background_end_color"
android:gradientRadius="@fraction/my_background_gradient_radius_percent"
android:type="radial" />
</shape>
此视图的宽度和高度均为match_parent。