Instantly share code, notes, and snippets.
Last active
September 22, 2017 00:06
-
Save kkuivi/2f886ca1a8f8adf608aeefa5db0eb6ac to your computer and use it in GitHub Desktop.
ToggleableButton - Easy way to create button with click/unclick functionality for Android.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- This should be in res/values/attrs.xml --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="ToggleableButton"> | |
<attr name="count" format="integer" /> | |
<attr name="icon" format="reference" /> | |
<attr name="active_icon" format="reference" /> | |
<attr name="active" format="boolean" /> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- This should be in your res/layout directory --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout | |
android:id="@+id/container_toggleablebutton" | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:orientation="horizontal"> | |
<ImageView | |
android:id="@+id/customview_toggleablebutton_iv_icon" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:gravity="left" | |
android:padding="5dp"/> | |
<TextView | |
android:id="@+id/customview_toggleablebutton_tv_count" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:gravity="right" | |
android:text="100" | |
android:paddingTop="12dp" | |
android:textAppearance="?android:attr/textAppearanceSmall" | |
android:textStyle="bold"/> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.os.Parcelable; | |
import android.support.v4.content.ContextCompat; | |
import android.text.TextUtils; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.view.MotionEvent; | |
import android.widget.ImageView; | |
import android.widget.LinearLayout; | |
import android.widget.TextView; | |
import com.squareup.picasso.Picasso; | |
/** | |
* Created by ekuivi on 8/2/17. | |
*/ | |
public class ToggleableButton extends LinearLayout{ | |
private TextView mCountTv; | |
private ImageView mIcon; | |
private Drawable mInactiveIcon; | |
private Drawable mActiveIcon; | |
private boolean mClickToggleEnable = false; | |
private boolean mActive = false; | |
private OnClickToggleListener mOnClickToggleListener; | |
public interface OnClickToggleListener { | |
void onClicked(); | |
void onUnclicked(); | |
} | |
private class ToggleableButtonAttributes { | |
int mCount = 0; | |
ToggleableButtonAttributes(int count) { | |
mCount = count; | |
} | |
ToggleableButtonAttributes(){} | |
} | |
public ToggleableButton(Context context) { | |
this(context, null); | |
} | |
public ToggleableButton(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public ToggleableButton(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
ToggleableButtonAttributes toggleableButtonAttributes = setupAttributes(context, attrs); | |
init(toggleableButtonAttributes); | |
} | |
private ToggleableButtonAttributes setupAttributes(Context context, AttributeSet attrs) { | |
ToggleableButtonAttributes result = new ToggleableButtonAttributes(); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToggleableButton); | |
try{ | |
int count = a.getInt(R.styleable.ToggleableButton_count, 0); | |
mActiveIcon = a.getDrawable(R.styleable.ToggleableButton_active_icon); | |
mInactiveIcon = a.getDrawable(R.styleable.ToggleableButton_icon); | |
mActive = a.getBoolean(R.styleable.ToggleableButton_active, false); | |
result.mCount = count; | |
} | |
finally { | |
a.recycle(); | |
} | |
return result; | |
} | |
@TargetApi(Build.VERSION_CODES.LOLLIPOP) | |
public ToggleableButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | |
super(context, attrs, defStyleAttr, defStyleRes); | |
ToggleableButtonAttributes toggleableButtonAttributes = setupAttributes(context, attrs); | |
init(toggleableButtonAttributes); | |
} | |
/** | |
* Initialize view | |
*/ | |
private void init(ToggleableButtonAttributes toggleableButtonAttributes) { | |
inflate(getContext(), R.layout.customview_toggleabblebutton, this); | |
setSaveEnabled(true); | |
mCountTv = (TextView) findViewById(R.id.customview_toggleablebutton_tv_count); | |
mIcon = (ImageView) findViewById(R.id.customview_toggleablebutton_iv_icon); | |
setCountValue(toggleableButtonAttributes.mCount); | |
setIconBasedOnActive(mActive); | |
Log.d("init", "init called"); | |
} | |
public int getCountValue() { | |
String countStr = mCountTv.getText().toString(); | |
if(TextUtils.isEmpty(countStr) || !TextUtils.isDigitsOnly(countStr)) | |
return 0; | |
return Integer.parseInt(countStr); | |
} | |
public void setCountValue(int count) { | |
String str = String.valueOf(count); | |
mCountTv.setText(str); | |
} | |
public void incrementCount() { | |
int count = getCountValue() + 1; | |
setCountValue(count); | |
} | |
public void decrementCount() { | |
int count = getCountValue() - 1; | |
setCountValue(count); | |
} | |
public void setIcon(Drawable drawable) { | |
if(drawable == null) { | |
Drawable defaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.ic_favorite_border); // use default icon of your choice | |
mIcon.setImageDrawable(defaultIcon); | |
} | |
mIcon.setImageDrawable(drawable); | |
} | |
public void setIcon(int id) { | |
Picasso.with(getContext()).load(id).placeholder(R.drawable.ic_favorite_border).error(R.drawable.ic_favorite_border).into(mIcon); // use default and error icons of your choice | |
} | |
public void setActive(boolean active) { | |
mActive = active; | |
setIconBasedOnActive(active); | |
} | |
public void enableClickToggle(boolean enable) { | |
mClickToggleEnable = enable; | |
} | |
@Override | |
public void setOnClickListener(OnClickListener onClickListener) { | |
super.setOnClickListener(onClickListener); | |
} | |
public void setOnClickToggleListener(OnClickToggleListener onClickToggleListener) { | |
mOnClickToggleListener = onClickToggleListener; | |
} | |
@Override | |
public boolean onTouchEvent( MotionEvent event) { | |
if(event.getAction() == MotionEvent.ACTION_DOWN){ | |
return performClick(); | |
} | |
return true; | |
} | |
@Override | |
public boolean performClick() { | |
if(mClickToggleEnable) { | |
if(mOnClickToggleListener != null) { | |
performToggle(); | |
return true; | |
} | |
else | |
return false; | |
} | |
else { | |
return super.performClick(); | |
} | |
} | |
public void performToggle() { | |
mActive = !mActive; | |
setIconBasedOnActive(mActive); | |
if(mActive) | |
mOnClickToggleListener.onClicked(); | |
else | |
mOnClickToggleListener.onUnclicked(); | |
} | |
private void setIconBasedOnActive(boolean active) { | |
if(active && mActiveIcon != null) | |
setIcon(mActiveIcon); | |
else if(!active && mIcon != null) | |
setIcon(mInactiveIcon); | |
} | |
@Override | |
public Parcelable onSaveInstanceState() { | |
Bundle bundle = new Bundle(); | |
bundle.putParcelable("instanceState", super.onSaveInstanceState()); | |
bundle.putBoolean("clickToggleEnable", mClickToggleEnable); | |
bundle.putBoolean("active", mActive); | |
return bundle; | |
} | |
@Override | |
public void onRestoreInstanceState(Parcelable state) { | |
if(state instanceof Bundle) { | |
Bundle bundle = (Bundle) state; | |
mClickToggleEnable = bundle.getBoolean("clickToggleEnable"); | |
mActive = bundle.getBoolean("active"); | |
} | |
super.onRestoreInstanceState(state); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ToggleableButton
ToggleableButton is a library that allows you to create a button similar to:
Basic Usage
Copy all the files above
Attributes
The attributes that can be used to configure the button's behavior and appearance are:
Button State
To set the initial active state of the button you simply use the setActive() functionality via XML or Java. This will show the button in the click/unclicked state(depending on the active state) with the drawable that you selected.
XML
app:active="true"
Java
button.setActive(true)
You can also set the count of the button using the setCountValue() functionality via XML or Java:
XML
app:count="3"
Java
button.setCountValue(5)
OR
To increment the count use:
button.incrementCount()
To decrement the count use:
button.decrementCount()
Button Event Listener
To make the button toggleable and listen for click/unclick events:
You can also set the button to behave like a normal button, i.e. listen for only click events. To make the button behave like a normal button:
Example
To create this button:
XML
Icons can be found at Icons8
Java
Dependencies
Picasso