我想扩展LinearLayout
,以便在绘制布局时在其下方添加投影。我玩过覆盖onDraw
方法,但我有点失落。任何有关这个甚至图书馆建议的帮助将不胜感激!
这是我想要实现的投影视图的示例。我不相信我可以在这里使用九个补丁因为我需要视图的内容在白框内。这意味着我需要知道边界与PNG末端之间的距离。但是我认为不同的屏幕密度意味着这个距离将始终是相同的PX但不是相同的DP。
所以要清楚我需要一种方法来扩展View类,以便在将它添加到布局时在其下面绘制阴影。请不要使用XML或9Patch解决方案。
由于
杰克
答案 0 :(得分:14)
我同意你对你的问题的评论:程序化的阴影效果是一个糟糕的选择,你可以通过简单的9patch(或其中一组)来达到同样的效果,如here所述。
顺便说一下,我太好奇了,最后我下班后解决了一个解决方案。
提供的代码是一个测试,应该作为一个简单的概念验证(所以请不要downvote)。显示的某些操作相当昂贵,并且可能严重影响性能(周围有许多示例,请here,here得到一个主意)。它应该是 最后的解决方案 ,仅适用于一次性显示的组件。
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(...)
那样处理Paint
。基本上,您应该为用于在自定义视图的Canvas
上绘制的Paint
对象定义 阴影图层 。遗憾的是,您无法使用res/drawable/mdpi
对象绘制NinePatchDrawable,因此您需要将其转换为Bitmap(第1次黑客攻击)。此外,似乎阴影图层无法与ARGB_8888图像一起正常工作,所以我找到的唯一方法是获得正确的阴影,就是在其下方绘制给定NinePatchDrawable(第二个黑客)的alpha蒙版。
这是一些sshots(在Android 2.3.3@mdpi和4.2.2@xhdpi上测试过)
编辑:为了彻底,我附上了测试中使用的9patch(置于{{1}})
答案 1 :(得分:3)
尝试这种技巧。
<强> container_dropshadow.xml 强>
`
<!-- Drop Shadow Stack -->
<item>
<shape>
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
<solid android:color="#00CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
<solid android:color="#10CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
<solid android:color="#20CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
<solid android:color="#30CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
<solid android:color="#50CCCCCC" />
</shape>
</item>
<!-- Background -->
<item>
<shape>
<solid android:color="@color/white" />
<corners android:radius="3dp" />
</shape>
</item>
然后,您可以将其作为背景应用于XML布局,如
LinearLayout android:background =“@ drawable / container_dropshadow”
`
答案 2 :(得分:3)
这是将阴影投射到布局,按钮等任何事物的最简单方法。 background.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<shape
android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
<corners android:radius="5dp"/>
</shape>
</item>
<item android:right="1dp" android:left="1dp" android:bottom="2dp">
<shape
android:shape="rectangle">
<solid android:color="@android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
在你的main.xml
中<LineaLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/background"
/>