6

i make a class extends LinearLayout i want to show a Rect like this:

   ---------------------     => it is round corner 
 | border frame         | .
 |  -----------------   | .
 |  |  hearder      |   | .
 |  | - - - - - - - |   | .
 |  |  center       |   | .
 |  |               |   | .
 |  | - - - - - - - |   | .
 |  |  buttom       |   | .
 |  ----------------    | .
 |                      | .
  ---------------------- .
  . . . . .  . . . . . .      => it is shadow

and i used paintShadow.setShadowLayer(this.radius, 8, 8, Color.GRAY); the shadow is not round.

so who kowns how to make a round rect and shadow. code:

@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();
    }
}
zt9788
  • 948
  • 4
  • 16
  • 31
  • 2
    In my opinion your best bet would be to use ninepatch background with rounded corner and dropshadow. – Avinazz Jan 26 '13 at 06:32
  • Background size a lot, so I want to use drawing mode – zt9788 Jan 26 '13 at 06:34
  • No problem. ninepatch will still do. Its a stretchable background thus reducing the resource size and other overheads. – Avinazz Jan 26 '13 at 06:39
  • @Avinazz thanks,I've been looking for something about niniepatch content, it is useful, but with the way of draw cannot come true? – zt9788 Jan 26 '13 at 06:43
  • hmmm, it needs a designer who knows ninepatching. The trick is to use padding and Textarea of ninepatch intelligently. I have done substantial work with ninepatch, thus I can say, a proper ninepatch is your solution. – Avinazz Jan 26 '13 at 06:50
  • 1
    @Avinazz thank you , It seems that I had to learn the ninepatch – zt9788 Jan 26 '13 at 06:54

4 Answers4

4

I'm willing to bet your problem is in using clipPath(). Try disabling hardware acceleration in the view, and I think you'll find that it works as expected.

In your init() method:

setLayerType(LAYER_TYPE_SOFTWARE, null);

Useful Links:

Community
  • 1
  • 1
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • thank you,where is the method of setLayerType? i could not find it in Paint class or LinearLayout. can you post some code for this question? – zt9788 Jan 26 '13 at 07:46
  • It's in the View class, but it's API 11+. Are you having this issue on a 2.2 device? – Kevin Coppock Jan 26 '13 at 08:20
  • my device is 4.X but i have to support 2.2 – zt9788 Jan 26 '13 at 08:23
  • As long as your targetSdk is 11 or higher (which it should be -- your minSdk can stay at 8), you can selectively disable hardware acceleration using `if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { setLayerType(LAYER_TYPE_SOFTWARE, null); }` – Kevin Coppock Jan 26 '13 at 08:30
3

Use nine-patch drawables. These will save you a lot of code. Check out some tutorials for nine-patch.

Also, have a look in your <SDK folder>/platforms/<android-xx>/data/res , development platforms ship with many ready made nine-patch drawables of default theme, you can copy these in your App.

Code example :

    @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);

    }
S.D.
  • 29,290
  • 3
  • 79
  • 130
  • thank you too,i will learn the ninepatch. i just wanna kown,is the way of draw can do it? and how. – zt9788 Jan 26 '13 at 07:47
0

instead of using setShadowlayer, directly draw a round-rect with alpha in color value like color=0x66000000. for a simple blackish shadow.

you can adjust it by changing the rect parameter and later on accommodating the other drawing to match with it, otherwise it will all be overwritten

rock_win
  • 755
  • 1
  • 5
  • 14
  • It seems it is difficult to reach the shadow of the gradual change effect. – zt9788 Jan 26 '13 at 07:22
  • Well in the layer below, rather than using a solid color like 0x66000000 , you can also try a `gradient` with start color, end color and center color to have the shadow color change gradually. – rock_win Feb 02 '13 at 05:01
0

there is a nice tutorial just about this matter , made by Romain Guy , here .

the only drawback i've found is that you need to prepare the bitmap to the exact size you wish to use it, otherwise it will smear.

android developer
  • 114,585
  • 152
  • 739
  • 1,270