package com.android.deskclock.widget; /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Outline; import android.graphics.Path; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; import androidx.appcompat.widget.AppCompatButton; import com.android.deskclock.R; /** * A MotionButton is an AppCompatButton that can round its edges. Added in 2.0 *

* Subclass of AppCompatButton to handle rounding edges dynamically. *

*

MotionButton attributes

* round * (id) call the TransitionListener with this trigger id * * * roundPercent * Set the corner radius of curvature as a fraction of the smaller side. * For squares 1 will result in a circle * * * round * Set the corner radius of curvature as a fraction of the smaller side. * For squares 1 will result in a circle * * * */ public class MotionButton extends AppCompatButton { private float mRoundPercent = 0; // rounds the corners as a percent private float mRound = Float.NaN; // rounds the corners in dp if NaN RoundPercent is in effect private Path mPath; ViewOutlineProvider mViewOutlineProvider; RectF mRect; public MotionButton(Context context) { super(context); init(context, null); } public MotionButton(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public MotionButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { setPadding(0, 0, 0, 0); if (attrs != null) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MotionButton); final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { int attr = a.getIndex(i); if (attr == R.styleable.MotionButton_round) { setRound(a.getDimension(attr, 0)); } else if (attr == R.styleable.MotionButton_roundPercent) { setRoundPercent(a.getFloat(attr, 0)); } } a.recycle(); } } /** * Set the corner radius of curvature as a fraction of the smaller side. * For squares 1 will result in a circle * * @param round the radius of curvature as a fraction of the smaller width */ public void setRoundPercent(float round) { boolean change = (mRoundPercent != round); mRoundPercent = round; if (mRoundPercent != 0.0f) { if (mPath == null) { mPath = new Path(); } if (mRect == null) { mRect = new RectF(); } if (mViewOutlineProvider == null) { mViewOutlineProvider = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { int w = getWidth(); int h = getHeight(); float r = Math.min(w, h) * mRoundPercent / 2; outline.setRoundRect(0, 0, w, h, r); } }; setOutlineProvider(mViewOutlineProvider); } setClipToOutline(true); int w = getWidth(); int h = getHeight(); float r = Math.min(w, h) * mRoundPercent / 2; mRect.set(0, 0, w, h); mPath.reset(); mPath.addRoundRect(mRect, r, r, Path.Direction.CW); } else { setClipToOutline(false); } if (change) { invalidateOutline(); } } /** * Set the corner radius of curvature * * @param round the radius of curvature NaN = default meaning roundPercent in effect */ public void setRound(float round) { if (Float.isNaN(round)) { mRound = round; float tmp = mRoundPercent; mRoundPercent = -1; setRoundPercent(tmp); // force eval of roundPercent return; } boolean change = (mRound != round); mRound = round; if (mRound != 0.0f) { if (mPath == null) { mPath = new Path(); } if (mRect == null) { mRect = new RectF(); } if (mViewOutlineProvider == null) { mViewOutlineProvider = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { int w = getWidth(); int h = getHeight(); outline.setRoundRect(0, 0, w, h, mRound); } }; setOutlineProvider(mViewOutlineProvider); } setClipToOutline(true); int w = getWidth(); int h = getHeight(); mRect.set(0, 0, w, h); mPath.reset(); mPath.addRoundRect(mRect, mRound, mRound, Path.Direction.CW); } else { setClipToOutline(false); } if (change) { invalidateOutline(); } } }