安卓如何绘制圆角矩形和阴影布局。

6
我创建了一个继承自LinearLayout的类。我想要显示一个矩形,就像这样:
   ---------------------     => it is round corner 
 | border frame         | .
 |  -----------------   | .
 |  |  hearder      |   | .
 |  | - - - - - - - |   | .
 |  |  center       |   | .
 |  |               |   | .
 |  | - - - - - - - |   | .
 |  |  buttom       |   | .
 |  ----------------    | .
 |                      | .
  ---------------------- .
  . . . . .  . . . . . .      => it is shadow

我使用了paintShadow.setShadowLayer(this.radius, 8, 8, Color.GRAY);然而,阴影并不是圆形的。

有谁知道如何制作圆角矩形和阴影?

代码:

@SuppressLint("DrawAllocation")
public class CornerLinearLayout extends LinearLayout{

    public CornerLinearLayout(Context context,AttributeSet attr){
        super(context,attr);
        init();
    }

    public CornerLinearLayout(Context context) {
        super(context);

        init();

        // TODO Auto-generated constructor stub
    }
    private static final int RADIUS=10;
    private int frameColor;
    private int radius;
    private Path mClip;
    private int frameWidth;
    private int headerHeight;
    private int buttomHeight;
    private int headerColor;
    private int buttomColor;
    private int centerColor;
    private void init() {
        this.radius = RADIUS;
        this.frameColor = 0xFFFFFFFF;
        this.frameWidth = 4;
        this.headerHeight = 50;
        this.buttomHeight = 50;
        headerColor = 0xFF31234A;
        buttomColor = 0xFF9ACFFF;
        centerColor = 0xFF55AACC;
        this.setBackgroundColor(0);
//      GradientDrawable gd = new GradientDrawable();
//      gd.setStroke(frameWidth, frameColor);
//      gd.setCornerRadius(radius);
//      gd.setColor(0);
//      //gd.setStroke(30, 0xFFFFFFFF);
//      
//      setBackgroundDrawable(gd);
        this.setPadding(frameWidth, frameWidth, frameWidth,frameWidth);

//      LinearLayout.LayoutParams params = (LayoutParams) this.getLayoutParams();
//      params.setMargins(25, 10, 25, 10);

    }
    private Paint paintShadow = new Paint();
    private Paint paint = new Paint();
    public void onDraw(Canvas canvas){
        super.onDraw(canvas);       
        RectF rf = new RectF(0,0,this.getWidth()-10,this.getHeight()-5);
        paintShadow.setShadowLayer(this.radius, 8, 8, Color.GRAY);
        rf.right -= 3;
        rf.bottom -= 3;
        paintShadow.setColor(this.frameColor);
        paintShadow.setStrokeWidth(5);
        canvas.drawRoundRect(rf,this.radius,this.radius, paintShadow);

        paint.setStyle(Paint.Style.FILL);
//      Rect r = new Rect(5,5,this.getWidth()-5,this.getHeight()-5);
        if(this.centerColor != 0){

            paint.setColor(this.centerColor);
//          canvas.drawRect(r, paint);
            rf.right -= 5;
            rf.left += 5;
            rf.top += 5;
            rf.bottom -=5;
            canvas.drawRoundRect(rf, this.radius, this.radius, paint);
        }
//      if(this.headerColor!=0){
//          Rect rr = new Rect(10,10,this.getWidth()-5,this.headerHeight-10);
//          paint.setColor(this.headerColor);
//          canvas.drawRect(rr, paint);
//      }
//      if(this.buttomColor != 0){
//          Rect rr = new Rect(10,this.getHeight()-this.buttomHeight,this.getWidth()-3,this.buttomHeight-3);
//          paint.setColor(this.headerColor);
//          canvas.drawRect(rr, paint);
//      }
//      


    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mClip = new Path();
        RectF rect = new RectF(0, 0, w, h);
        mClip.addRoundRect(rect, this.radius,  this.radius, Direction.CW);

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();

        canvas.clipPath(mClip);

        super.dispatchDraw(canvas);
        canvas.restore();
    }
}

2
在我看来,你最好使用带有圆角和阴影的九宫格背景。 - Avinazz
背景大小很大,因此我想使用绘图模式。 - zt9788
没问题。NinePatch 仍然可以使用。它是一种可伸缩的背景,从而减少资源大小和其他开销。 - Avinazz
@Avinazz 谢谢,我一直在寻找关于 Niniepatch 内容的资料,很有用,但是用绘图的方式无法实现吗? - zt9788
嗯,它需要一个懂得九宫格技术的设计师。诀窍在于聪明地使用九宫格的填充和文本区域。我已经做了大量的九宫格工作,因此我可以说,一个合适的九宫格是你的解决方案。 - Avinazz
1
@Avinazz 谢谢你,看来我得学习一下NinePatch。 - zt9788
4个回答

4

谢谢,setLayerType方法在哪里?我在Paint类或LinearLayout中找不到它。你能发一些代码来回答这个问题吗? - zt9788
它在View类中,但是它是API 11+。你在2.2设备上遇到了这个问题吗? - Kevin Coppock
我的设备是4.X,但我必须支持2.2。 - zt9788
只要您的 targetSdk 是 11 或更高版本(应该是这样的 - minSdk 可以保持在 8),您可以使用“if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { setLayerType(LAYER_TYPE_SOFTWARE, null); }”来有选择性地禁用硬件加速。 - Kevin Coppock

3
使用九宫格可拉伸图片。这将节省大量代码。查看一些九宫格教程
此外,请查看您的<SDK文件夹>/platforms/<android-xx>/data/res,开发平台附带许多默认主题的现成九宫格可拉伸图片,您可以将这些复制到您的应用程序中。
代码示例:
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //-- draw with white color--
        Paint p = new Paint();
        p.setColor(Color.WHITE);

        //-- set shadow, 5dp down, 5 dp left, with radius of 15 dp--
        p.setShadowLayer(10,5,5,Color.BLACK);

        //-- warning, Honeycomb and above only
        //-- this will reduce draw performance of view
        //-- but is required to support drawing filters, like shadow, blur etc
        setLayerType(LAYER_TYPE_SOFTWARE,p);

        //--basic shapes don't have round corners yet, so use path--
        Path pt = new Path();

        //-- round rectangle path with 15dp padding (space for shadow)
        //-- and 10 dp corner radius
        pt.addRoundRect(new RectF(15,15,getWidth() - 15 ,getHeight() -15 ),
                        10,10, Path.Direction.CW);

        //--draw--
        canvas.drawPath(pt,p);

    }

谢谢,我也会学习Ninepatch。我只是想知道,能否用绘图的方式实现?如何实现呢? - zt9788

0

不要使用setShadowlayer,而是直接绘制一个带有alpha的圆角矩形,例如color=0x66000000,以获得简单的黑色阴影。

您可以通过更改rect参数来调整它,然后再适应其他绘图与之匹配,否则所有内容都将被覆盖。


似乎很难达到渐变效果的阴影。 - zt9788
在下一层中,与其使用像0x66000000这样的纯色,你也可以尝试使用渐变,包括起始颜色、结束颜色和中心颜色,以实现阴影颜色逐渐变化的效果。 - rock_win

0

有一个非常好的教程,关于这个问题,是由Romain Guy制作的,在这里

我发现唯一的缺点是你需要准备位图到你希望使用的精确尺寸,否则它会模糊。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接