扩展Android View类以添加一个drophadow

Jac*_*ney 11 inheritance android view android-layout android-view

我想进行扩展,LinearLayout以便在绘制布局时在其下方添加一个投影.我玩过这种onDraw方法但是我有点迷失了.任何有关这个甚至图书馆建议的帮助将不胜感激!

这是我想要实现的投影视图的示例.我不相信我可以在这里使用九个补丁因为我需要视图的内容在白框内.这意味着我需要知道边界与PNG末端之间的距离.但是我相信不同的屏幕密度意味着这个距离将始终是相同的PX但不是相同的DP.

所以要清楚我需要一种方法来扩展View类,以便在将它添加到布局时在其下面绘制阴影.请不要使用XML或9Patch解决方案.

在此输入图像描述

谢谢

插口

a.b*_*cci 15

我同意你的问题的意见:方案阴影效果的影响是一个不错的选择,你可以实现一个简单的9patch(或一组人)相同的效果喜欢称这里.

顺便说一下,我太好奇了,最后我下班后解决了一个解决方案.

提供的代码是一个测试,应该作为一个简单的概念验证(所以请不要downvote).显示的一些操作非常昂贵,并且可能会严重影响性能(周围有很多例子,看这里,这里有个想法).它应该是仅适用于一次性显示的组件的最后解决方案.

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

首先,为了获得程序化的投影,你必须Paint.setShadowLayer(...)这里所说的那样处理.基本上,您应该为用于在自定义视图上绘制的对象定义阴影图层.遗憾的是,您不能使用对象来绘制NinePatchDrawable,因此您需要将其转换为Bitmap(第1次黑客攻击).此外,似乎阴影图层无法与ARGB_8888图像一起正常工作,因此我发现为获得正确阴影的唯一方法是在其下方绘制给定NinePatchDrawable(第二个黑客)的alpha蒙版.PaintCanvasPaint

这是一些sshots(在Android 2.3.3@mdpi和4.2.2@xhdpi上测试) 在此输入图像描述 在此输入图像描述

编辑:为了彻底,我附上了测试中使用的9patch(放入res/drawable/mdpi) 在此输入图像描述

  • @JackMahoney抱歉,但你错了.只需看看上面的截图:有2个不同的**真实设备**:320x480 | mdpi,720x1280 | xhdpi.在这两种情况下都使用相同的9patch.您可以在每个sshot中以像素为单位测量气球的圆角,您会注意到xhdpi的宽度是mdpi的2倍.填充(在9patch中定义)也相应地扩展. (2认同)