Home | History | Annotate | Download | only in shapes
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.graphics.drawable.shapes;
     18 
     19 import android.graphics.Canvas;
     20 import android.graphics.Outline;
     21 import android.graphics.Paint;
     22 import android.graphics.Path;
     23 import android.graphics.RectF;
     24 
     25 /**
     26  * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
     27  * can be included (to make a sort of "O" shape).
     28  * The rounded rectangle can be drawn to a Canvas with its own draw() method,
     29  * but more graphical control is available if you instead pass
     30  * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
     31  */
     32 public class RoundRectShape extends RectShape {
     33     private float[] mOuterRadii;
     34     private RectF   mInset;
     35     private float[] mInnerRadii;
     36 
     37     private RectF mInnerRect;
     38     private Path  mPath;    // this is what we actually draw
     39 
     40     /**
     41      * RoundRectShape constructor.
     42      * Specifies an outer (round)rect and an optional inner (round)rect.
     43      *
     44      * @param outerRadii An array of 8 radius values, for the outer roundrect.
     45      *                   The first two floats are for the
     46      *                   top-left corner (remaining pairs correspond clockwise).
     47      *                   For no rounded corners on the outer rectangle,
     48      *                   pass null.
     49      * @param inset      A RectF that specifies the distance from the inner
     50      *                   rect to each side of the outer rect.
     51      *                   For no inner, pass null.
     52      * @param innerRadii An array of 8 radius values, for the inner roundrect.
     53      *                   The first two floats are for the
     54      *                   top-left corner (remaining pairs correspond clockwise).
     55      *                   For no rounded corners on the inner rectangle,
     56      *                   pass null.
     57      *                   If inset parameter is null, this parameter is ignored.
     58      */
     59     public RoundRectShape(float[] outerRadii, RectF inset,
     60                           float[] innerRadii) {
     61         if (outerRadii != null && outerRadii.length < 8) {
     62             throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values");
     63         }
     64         if (innerRadii != null && innerRadii.length < 8) {
     65             throw new ArrayIndexOutOfBoundsException("inner radii must have >= 8 values");
     66         }
     67         mOuterRadii = outerRadii;
     68         mInset = inset;
     69         mInnerRadii = innerRadii;
     70 
     71         if (inset != null) {
     72             mInnerRect = new RectF();
     73         }
     74         mPath = new Path();
     75     }
     76 
     77     @Override
     78     public void draw(Canvas canvas, Paint paint) {
     79         canvas.drawPath(mPath, paint);
     80     }
     81 
     82     @Override
     83     public void getOutline(Outline outline) {
     84         if (mInnerRect != null) return; // have a hole, can't produce valid outline
     85 
     86         float radius = 0;
     87         if (mOuterRadii != null) {
     88             radius = mOuterRadii[0];
     89             for (int i = 1; i < 8; i++) {
     90                 if (mOuterRadii[i] != radius) {
     91                     // can't call simple constructors, use path
     92                     outline.setConvexPath(mPath);
     93                     return;
     94                 }
     95             }
     96         }
     97 
     98         final RectF rect = rect();
     99         outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
    100                 (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
    101                 radius);
    102     }
    103 
    104     @Override
    105     protected void onResize(float w, float h) {
    106         super.onResize(w, h);
    107 
    108         RectF r = rect();
    109         mPath.reset();
    110 
    111         if (mOuterRadii != null) {
    112             mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW);
    113         } else {
    114             mPath.addRect(r, Path.Direction.CW);
    115         }
    116         if (mInnerRect != null) {
    117             mInnerRect.set(r.left + mInset.left, r.top + mInset.top,
    118                            r.right - mInset.right, r.bottom - mInset.bottom);
    119             if (mInnerRect.width() < w && mInnerRect.height() < h) {
    120                 if (mInnerRadii != null) {
    121                     mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW);
    122                 } else {
    123                     mPath.addRect(mInnerRect, Path.Direction.CCW);
    124                 }
    125             }
    126         }
    127     }
    128 
    129     @Override
    130     public RoundRectShape clone() throws CloneNotSupportedException {
    131         RoundRectShape shape = (RoundRectShape) super.clone();
    132         shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null;
    133         shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null;
    134         shape.mInset = new RectF(mInset);
    135         shape.mInnerRect = new RectF(mInnerRect);
    136         shape.mPath = new Path(mPath);
    137         return shape;
    138     }
    139 }
    140