android - 扩展 Android View 类以添加阴影

标签 android android-layout inheritance view android-view

我想扩展 LinearLayout 以便在绘制布局时在其下方添加阴影。我试过重写 onDraw 方法,但我有点迷路了。非常感谢对此甚至图书馆建议的任何帮助!

这是我试图实现的投影 View 的示例。我不相信我可以在这里使用 9-patch ,因为我需要 View 的内容在白框中。这意味着我需要知道边界和 PNG 末尾之间的距离。然而,我相信不同的屏幕密度意味着这个距离将始终是相同的 PX 而不是相同的 DP。

明确地说,我需要一种方法来扩展 View 类,以便在将其添加到布局时在其下方绘制阴影。请不要使用 XML 或 9Patch 解决方案。

enter image description here

谢谢

jack

最佳答案

我同意对你的问题的评论:程序化阴影效果是一个糟糕的选择,你可以用一个简单的 9patch(或一组)来实现相同的效果,如 here 所述.

顺便说一句,我太好奇了,下类后我最终破解了一个解决方案。

提供的代码是一个测试,应该作为一个简单的概念验证(所以请不要投反对票)。显示的一些操作相当昂贵,并且可能严重影响性能(周围有很多示例,请查看 herehere 以获得想法) .它应该是不得已的解决方案,仅适用于偶尔显示的组件。

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(...),如 here 所述.基本上,您应该为用于在自定义 View 的 Canvas 上绘制的 Paint 对象定义一个阴影层。不幸的是,您不能使用 Paint 对象来绘制 NinePatchDrawable,因此您需要将其转换为位图(第 1 次 hack)。此外,阴影层似乎无法与 ARGB_8888 图像一起正常工作,因此我发现获得正确阴影的唯一方法是在其下方绘制给定 NinePatchDrawable(第二个 hack)的 alpha 蒙版。

这里有几个截图(在 Android 2.3.3@mdpi 和 4.2.2@xhdpi 上测试) enter image description here enter image description here

编辑:为了彻底,我附上了测试中使用的 9patch(放在 res/drawable/mdpi 中) enter image description here

关于android - 扩展 Android View 类以添加阴影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14930984/

相关文章:

c++ - 通过指向派生类的指针访问派生成员变量

python - 使用其他类的方法而不继承

按下后退按钮时android黑屏

android - TextView 因 android 中父级的 LinearLayout wrap_content 而断线

android - Android 中的 HttpClient 身份验证

java - 我如何从好友图像更改 Xmpp android 获得通知

java - 如何回收 LinearLayout 中的 View ,以避免多次调用 findViewById()?

c++ - 函数的多重声明

android - 在通用图像加载器中访问 protected 图像

android - devicePolicyManager.lockNow() 不适用于摩托罗拉平板电脑