扩展Android的View类添加阴影效果 [英] Extending Android View class to add a dropshadow

查看:832
本文介绍了扩展Android的View类添加阴影效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想扩展的LinearLayout 所以,当我的布局绘制阴影中加入下面。我打得周围覆盖的OnDraw 方法,但我有点失落。任何帮助,这甚至是图书馆建议将不胜AP preciated!

I want to extend LinearLayout so that when my layout is drawn a drop shadow is added underneath it. I've played around overriding the onDraw method but I'm a bit lost. Any help with this or even library suggestions would be greatly appreciated!

这里的阴影看法,我想实现的一个例子。我不相信,我可以用一个九补丁在这里,因为我需要的视图的内容是内部的白色盒子。这意味着我需要知道的边界和PNG的端之间的距离。不过,我相信不同的屏幕密度意味着这个距离始终是相同的PX但不是同一个DP。

Here's an example of the drop shadow view I am trying to achieve. I don't believe I can use a nine patch here because I need the contents of the view to be within the white box. This would mean I would need to know the distance between the border and the end of the PNG. However I believe different screen densities mean that this distance will always be the same PX but not the same DP.

所以要清楚,我需要一种方法来延伸,使得阴影下它绘制时,它被添加到布局视图类。没有XML或9Patch的解决方案吧。

So to be clear I need a way to extend the View class so that a drop shadow is drawn under it when it is added to a layout. No XML or 9Patch solutions please.

感谢

杰克

推荐答案

我同意你的问题的意见:方案阴影的效果是不错的选择,你可以实现一个简单的9patch同样的效果(或一组他们)喜欢这里规定

I agree with the comments on your question: programmatic dropshadow effect is a bad choice, and you could achieve the same effect with a simple 9patch (or a set of them) like stated here.

顺便说一句我太好奇了,我下班后黑客的解决方案结束。

BTW I was too curious, and I ended with hacking a solution after work.

的code presented是一个考验,并应旨在作为一个简单的概念验证的(所以请不要downvote)。有些显示的操作是挺贵,然后可能的上的表现严重影响(周围有很多例子,看看<一href="http://stackoverflow.com/questions/7523622/setshadowlayer-causes-slow-draw-time-in-gridview">here, <一href="http://stackoverflow.com/questions/8749906/android-canvas-setshadowlayer-greatly-decreases-performance">here得到一个想法)。这应该是一个最后一招解决方案仅用于显示一次在一个-而一个组成部分。

The code presented is a test, and should be intended as a simple proof-of-concept (so please don't downvote). Some of the operations shown are quite expensive, and may seriously impact on the performances (There are many examples around, look here, here to get an idea). It should be a last resort solution only for a component shown once-in-a-while.

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 。基本上你应该定义的阴影层作为用来吸取画布的油漆对象自定义视图中。不幸的是,你不能使用油漆对象绘制NinePatchDrawable,所以你需要将其转换成位图(第1黑客)。此外,它似乎像影子层无法与ARGB_8888图像正常工作,所以我发现,以获得正确的阴影的唯一途径已经提请给予NinePatchDrawable(第2黑客)仅低于本身的alpha遮罩。

First of all in order to get programmatic drop shadow you have to deal with Paint.setShadowLayer(...) like stated here. Basically you should define a shadow layer for the Paint object used to draw on the Canvas of your custom view. Unfortunately you cannot use a Paint object to draw a NinePatchDrawable, so you need to convert it into a Bitmap (1st hack). Furthermore it seems like shadow layers can't work properly with ARGB_8888 images, so the only way I found in order to get a proper shadow has been to draw the alpha mask of the given NinePatchDrawable (2nd hack) just below itself.

下面是几个sshots的(在Android 2.3.3@mdpi和4.2.2@xhdpi测试)

Here's a couple of sshots (tested on Android 2.3.3@mdpi and 4.2.2@xhdpi)

编辑:只是要彻底,我连着在测试中使用的9patch(放在 RES /绘制/ MDPI

just to be thorough, I attached the 9patch used in the test (placed in res/drawable/mdpi)

这篇关于扩展Android的View类添加阴影效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆