1*90c8c64dSAndroid Build Coastguard Worker /* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright 2014, The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.floatingactionbuttonbasic; 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker import android.content.Context; 20*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Outline; 21*90c8c64dSAndroid Build Coastguard Worker import android.util.AttributeSet; 22*90c8c64dSAndroid Build Coastguard Worker import android.view.View; 23*90c8c64dSAndroid Build Coastguard Worker import android.view.ViewOutlineProvider; 24*90c8c64dSAndroid Build Coastguard Worker import android.widget.Checkable; 25*90c8c64dSAndroid Build Coastguard Worker import android.widget.FrameLayout; 26*90c8c64dSAndroid Build Coastguard Worker 27*90c8c64dSAndroid Build Coastguard Worker /** 28*90c8c64dSAndroid Build Coastguard Worker * A Floating Action Button is a {@link android.widget.Checkable} view distinguished by a circled 29*90c8c64dSAndroid Build Coastguard Worker * icon floating above the UI, with special motion behaviors. 30*90c8c64dSAndroid Build Coastguard Worker */ 31*90c8c64dSAndroid Build Coastguard Worker public class FloatingActionButton extends FrameLayout implements Checkable { 32*90c8c64dSAndroid Build Coastguard Worker 33*90c8c64dSAndroid Build Coastguard Worker /** 34*90c8c64dSAndroid Build Coastguard Worker * Interface definition for a callback to be invoked when the checked state 35*90c8c64dSAndroid Build Coastguard Worker * of a compound button changes. 36*90c8c64dSAndroid Build Coastguard Worker */ 37*90c8c64dSAndroid Build Coastguard Worker public static interface OnCheckedChangeListener { 38*90c8c64dSAndroid Build Coastguard Worker 39*90c8c64dSAndroid Build Coastguard Worker /** 40*90c8c64dSAndroid Build Coastguard Worker * Called when the checked state of a FAB has changed. 41*90c8c64dSAndroid Build Coastguard Worker * 42*90c8c64dSAndroid Build Coastguard Worker * @param fabView The FAB view whose state has changed. 43*90c8c64dSAndroid Build Coastguard Worker * @param isChecked The new checked state of buttonView. 44*90c8c64dSAndroid Build Coastguard Worker */ onCheckedChanged(FloatingActionButton fabView, boolean isChecked)45*90c8c64dSAndroid Build Coastguard Worker void onCheckedChanged(FloatingActionButton fabView, boolean isChecked); 46*90c8c64dSAndroid Build Coastguard Worker } 47*90c8c64dSAndroid Build Coastguard Worker 48*90c8c64dSAndroid Build Coastguard Worker /** 49*90c8c64dSAndroid Build Coastguard Worker * An array of states. 50*90c8c64dSAndroid Build Coastguard Worker */ 51*90c8c64dSAndroid Build Coastguard Worker private static final int[] CHECKED_STATE_SET = { 52*90c8c64dSAndroid Build Coastguard Worker android.R.attr.state_checked 53*90c8c64dSAndroid Build Coastguard Worker }; 54*90c8c64dSAndroid Build Coastguard Worker 55*90c8c64dSAndroid Build Coastguard Worker private static final String TAG = "FloatingActionButton"; 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker // A boolean that tells if the FAB is checked or not. 58*90c8c64dSAndroid Build Coastguard Worker private boolean mChecked; 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Worker // A listener to communicate that the FAB has changed it's state 61*90c8c64dSAndroid Build Coastguard Worker private OnCheckedChangeListener mOnCheckedChangeListener; 62*90c8c64dSAndroid Build Coastguard Worker FloatingActionButton(Context context)63*90c8c64dSAndroid Build Coastguard Worker public FloatingActionButton(Context context) { 64*90c8c64dSAndroid Build Coastguard Worker this(context, null, 0, 0); 65*90c8c64dSAndroid Build Coastguard Worker } 66*90c8c64dSAndroid Build Coastguard Worker FloatingActionButton(Context context, AttributeSet attrs)67*90c8c64dSAndroid Build Coastguard Worker public FloatingActionButton(Context context, AttributeSet attrs) { 68*90c8c64dSAndroid Build Coastguard Worker this(context, attrs, 0, 0); 69*90c8c64dSAndroid Build Coastguard Worker } 70*90c8c64dSAndroid Build Coastguard Worker FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr)71*90c8c64dSAndroid Build Coastguard Worker public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { 72*90c8c64dSAndroid Build Coastguard Worker this(context, attrs, defStyleAttr, 0); 73*90c8c64dSAndroid Build Coastguard Worker } 74*90c8c64dSAndroid Build Coastguard Worker FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)75*90c8c64dSAndroid Build Coastguard Worker public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr, 76*90c8c64dSAndroid Build Coastguard Worker int defStyleRes) { 77*90c8c64dSAndroid Build Coastguard Worker super(context, attrs, defStyleAttr); 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker setClickable(true); 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker // Set the outline provider for this view. The provider is given the outline which it can 82*90c8c64dSAndroid Build Coastguard Worker // then modify as needed. In this case we set the outline to be an oval fitting the height 83*90c8c64dSAndroid Build Coastguard Worker // and width. 84*90c8c64dSAndroid Build Coastguard Worker setOutlineProvider(new ViewOutlineProvider() { 85*90c8c64dSAndroid Build Coastguard Worker @Override 86*90c8c64dSAndroid Build Coastguard Worker public void getOutline(View view, Outline outline) { 87*90c8c64dSAndroid Build Coastguard Worker outline.setOval(0, 0, getWidth(), getHeight()); 88*90c8c64dSAndroid Build Coastguard Worker } 89*90c8c64dSAndroid Build Coastguard Worker }); 90*90c8c64dSAndroid Build Coastguard Worker 91*90c8c64dSAndroid Build Coastguard Worker // Finally, enable clipping to the outline, using the provider we set above 92*90c8c64dSAndroid Build Coastguard Worker setClipToOutline(true); 93*90c8c64dSAndroid Build Coastguard Worker } 94*90c8c64dSAndroid Build Coastguard Worker 95*90c8c64dSAndroid Build Coastguard Worker /** 96*90c8c64dSAndroid Build Coastguard Worker * Sets the checked/unchecked state of the FAB. 97*90c8c64dSAndroid Build Coastguard Worker * @param checked 98*90c8c64dSAndroid Build Coastguard Worker */ setChecked(boolean checked)99*90c8c64dSAndroid Build Coastguard Worker public void setChecked(boolean checked) { 100*90c8c64dSAndroid Build Coastguard Worker // If trying to set the current state, ignore. 101*90c8c64dSAndroid Build Coastguard Worker if (checked == mChecked) { 102*90c8c64dSAndroid Build Coastguard Worker return; 103*90c8c64dSAndroid Build Coastguard Worker } 104*90c8c64dSAndroid Build Coastguard Worker mChecked = checked; 105*90c8c64dSAndroid Build Coastguard Worker 106*90c8c64dSAndroid Build Coastguard Worker // Now refresh the drawable state (so the icon changes) 107*90c8c64dSAndroid Build Coastguard Worker refreshDrawableState(); 108*90c8c64dSAndroid Build Coastguard Worker 109*90c8c64dSAndroid Build Coastguard Worker if (mOnCheckedChangeListener != null) { 110*90c8c64dSAndroid Build Coastguard Worker mOnCheckedChangeListener.onCheckedChanged(this, checked); 111*90c8c64dSAndroid Build Coastguard Worker } 112*90c8c64dSAndroid Build Coastguard Worker } 113*90c8c64dSAndroid Build Coastguard Worker 114*90c8c64dSAndroid Build Coastguard Worker /** 115*90c8c64dSAndroid Build Coastguard Worker * Register a callback to be invoked when the checked state of this button 116*90c8c64dSAndroid Build Coastguard Worker * changes. 117*90c8c64dSAndroid Build Coastguard Worker * 118*90c8c64dSAndroid Build Coastguard Worker * @param listener the callback to call on checked state change 119*90c8c64dSAndroid Build Coastguard Worker */ setOnCheckedChangeListener(OnCheckedChangeListener listener)120*90c8c64dSAndroid Build Coastguard Worker public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { 121*90c8c64dSAndroid Build Coastguard Worker mOnCheckedChangeListener = listener; 122*90c8c64dSAndroid Build Coastguard Worker } 123*90c8c64dSAndroid Build Coastguard Worker 124*90c8c64dSAndroid Build Coastguard Worker @Override isChecked()125*90c8c64dSAndroid Build Coastguard Worker public boolean isChecked() { 126*90c8c64dSAndroid Build Coastguard Worker return mChecked; 127*90c8c64dSAndroid Build Coastguard Worker } 128*90c8c64dSAndroid Build Coastguard Worker 129*90c8c64dSAndroid Build Coastguard Worker @Override toggle()130*90c8c64dSAndroid Build Coastguard Worker public void toggle() { 131*90c8c64dSAndroid Build Coastguard Worker setChecked(!mChecked); 132*90c8c64dSAndroid Build Coastguard Worker } 133*90c8c64dSAndroid Build Coastguard Worker 134*90c8c64dSAndroid Build Coastguard Worker /** 135*90c8c64dSAndroid Build Coastguard Worker * Override performClick() so that we can toggle the checked state when the view is clicked 136*90c8c64dSAndroid Build Coastguard Worker */ 137*90c8c64dSAndroid Build Coastguard Worker @Override performClick()138*90c8c64dSAndroid Build Coastguard Worker public boolean performClick() { 139*90c8c64dSAndroid Build Coastguard Worker toggle(); 140*90c8c64dSAndroid Build Coastguard Worker return super.performClick(); 141*90c8c64dSAndroid Build Coastguard Worker } 142*90c8c64dSAndroid Build Coastguard Worker 143*90c8c64dSAndroid Build Coastguard Worker @Override onSizeChanged(int w, int h, int oldw, int oldh)144*90c8c64dSAndroid Build Coastguard Worker protected void onSizeChanged(int w, int h, int oldw, int oldh) { 145*90c8c64dSAndroid Build Coastguard Worker super.onSizeChanged(w, h, oldw, oldh); 146*90c8c64dSAndroid Build Coastguard Worker 147*90c8c64dSAndroid Build Coastguard Worker // As we have changed size, we should invalidate the outline so that is the the 148*90c8c64dSAndroid Build Coastguard Worker // correct size 149*90c8c64dSAndroid Build Coastguard Worker invalidateOutline(); 150*90c8c64dSAndroid Build Coastguard Worker } 151*90c8c64dSAndroid Build Coastguard Worker 152*90c8c64dSAndroid Build Coastguard Worker @Override onCreateDrawableState(int extraSpace)153*90c8c64dSAndroid Build Coastguard Worker protected int[] onCreateDrawableState(int extraSpace) { 154*90c8c64dSAndroid Build Coastguard Worker final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 155*90c8c64dSAndroid Build Coastguard Worker if (isChecked()) { 156*90c8c64dSAndroid Build Coastguard Worker mergeDrawableStates(drawableState, CHECKED_STATE_SET); 157*90c8c64dSAndroid Build Coastguard Worker } 158*90c8c64dSAndroid Build Coastguard Worker return drawableState; 159*90c8c64dSAndroid Build Coastguard Worker } 160*90c8c64dSAndroid Build Coastguard Worker } 161