我同意您对问题的评论:程序化阴影效果是一个糟糕的选择,您可以使用此处所述的简单 9patch(或其中的一组)来实现相同的效果。
顺便说一句,我太好奇了,我下班后破解了一个解决方案。
提供的代码是一个测试,应该是一个简单的概念证明(所以请不要投反对票)。显示的一些操作非常昂贵,并且可能严重影响性能(周围有很多例子,看这里,这里得到一个想法)。对于偶尔显示的组件,它应该是最后的解决方案。
public class BalloonView extends TextView {
protected NinePatchDrawable bg;
protected Paint paint;
protected Rect padding = new Rect();
protected Bitmap bmp;
public BalloonView(Context context) {
super(context);
init();
}
public BalloonView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BalloonView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
@SuppressLint("NewApi")
protected void init() {
// decode the 9patch drawable
bg = (NinePatchDrawable) getResources().getDrawable(R.drawable.balloon);
// get paddings from the 9patch and apply them to the View
bg.getPadding(padding);
setPadding(padding.left, padding.top, padding.right, padding.bottom);
// prepare the Paint to use below
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.rgb(255,255,255));
paint.setStyle(Style.FILL);
// this check is needed in order to get this code
// working if target SDK>=11
if( Build.VERSION.SDK_INT >= 11 )
setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
// set the shadowLayer
paint.setShadowLayer(
padding.left * .2f, // radius
0f, // blurX
padding.left * .1f, // blurY
Color.argb(128, 0, 0, 0) // shadow color
);
}
@Override
protected void onDraw(Canvas canvas) {
int w = getMeasuredWidth();
int h = getMeasuredHeight();
// set 9patch bounds according to view measurement
// NOTE: if not set, the drawable will not be drawn
bg.setBounds(0, 0, w, h);
// this code looks expensive: let's do once
if( bmp == null ) {
// it seems like shadowLayer doesn't take into account
// alpha channel in ARGB_8888 sources...
bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888);
// draw the given 9patch on the brand new bitmap
Canvas tmp = new Canvas(bmp);
bg.draw(tmp);
// extract only the alpha channel
bmp = bmp.extractAlpha();
}
// this "alpha mask" has the same shape of the starting 9patch,
// but filled in white and **with the dropshadow**!!!!
canvas.drawBitmap(bmp, 0, 0, paint);
// let's paint the 9patch over...
bg.draw(canvas);
super.onDraw(canvas);
}
}
首先,为了获得程序化投影,您必须Paint.setShadowLayer(...)
像这里所述那样处理。基本上,您应该为用于在自定义视图上绘制的对象定义一个阴影层。不幸的是,您不能使用对象来绘制 NinePatchDrawable,因此您需要将其转换为位图(第一次 hack)。此外,阴影层似乎无法与 ARGB_8888 图像一起正常工作,因此我发现为了获得适当阴影的唯一方法是在其下方绘制给定 NinePatchDrawable(第二次 hack)的 alpha 蒙版。Paint
Canvas
Paint
这是几个截图(在 Android 2.3.3@mdpi 和 4.2.2@xhdpi 上测试)
编辑:为了彻底起见,我附上了测试中使用的 9patch(放置在res/drawable/mdpi
)