Buttons
Android design guides metrics: https://material.io/guidelines/layout/metrics-keylines.html# min button size = 48dp styles: https://stackoverflow.com/a/29848987/4656400 Custom Radio buttons https://crosp.net/blog/android/creating-custom-radio-groups-radio-buttons-android/
<resources>
<style name="button" parent="@android:style/Widget.Button">
<item name="android:gravity">center_vertical|center_horizontal</item>
<item name="android:textColor">#FFFFFFFF</item>
<item name="android:shadowColor">#FF000000</item>
<item name="android:shadowDx">0</item>
<item name="android:shadowDy">-1</item>
<item name="android:shadowRadius">0.2</item>
<item name="android:textSize">16dip</item>
<item name="android:textStyle">bold</item>
<item name="android:background">@drawable/button</item>
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorLightGray">
<item>
<shape
android:shape="rectangle">
<solid
android:color="@color/colorGrayAlpha" />
</shape>
</item>
</ripple>
/**
* Created by Admin on 11/4/16.
* custom toggle button with pictures instead of text
*/
class ImageToggleButton: ImageButton, Checkable {
private var mBroadcasting: Boolean = false
private var mChecked: Boolean = false
var drawableOn: Drawable? = null
var drawableOff: Drawable? = null
private var mOnCheckedChangeListener: OnCheckedChangeListener? = null
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
obtainStyledAttributes(context, attrs)
}
constructor(context: Context, attrs: AttributeSet): super(context, attrs) {
obtainStyledAttributes(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int): super(context, attrs, defStyleAttr, defStyleRes) {
obtainStyledAttributes(context, attrs)
}
private fun obtainStyledAttributes(context: Context, attrs: AttributeSet) {
val a = context.obtainStyledAttributes(attrs, R.styleable.ImageToggleButton, 0, 0)
drawableOn = a.getDrawable(R.styleable.ImageToggleButton_drawable_on)
drawableOff = a.getDrawable(R.styleable.ImageToggleButton_drawable_off)
isChecked = a.getBoolean(R.styleable.ImageToggleButton_checked, false)
a.recycle()
}
// Checkable methods
override fun isChecked() = mChecked
override fun toggle() {
isChecked = !mChecked
}
override fun setChecked(checked: Boolean) {
if (mChecked != checked) {
mChecked = checked
refreshDrawableState()
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) return
mBroadcasting = true
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener?.onCheckedChanged(this, mChecked)
}
mBroadcasting = false
}
syncDrawableState()
}
private fun syncDrawableState() {
val checked = isChecked
if (checked && drawableOn != null) {
setImageDrawable(drawableOn)
} else if (!checked && drawableOff != null) {
setImageDrawable(drawableOff)
}
}
// helper stuff
override fun performClick(): Boolean {
toggle()
val handled = super.performClick()
if (!handled) {
// View only makes a sound effect if the onClickListener was
// called, so we'll need to make one here instead.
playSoundEffect(SoundEffectConstants.CLICK)
}
return handled
}
// override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
// super.onLayout(changed, left, top, right, bottom)
// syncDrawableState()
// }
// listener stuff
/**
* Register a callback to be invoked when the checked state of this button
* changes.
* @param listener the callback to call on checked state change
*/
fun setOnCheckedChangeListener(listener: OnCheckedChangeListener) {
mOnCheckedChangeListener = listener
}
fun setOnCheckedChangeListener(callback: (buttonView: ImageToggleButton, isChecked: Boolean) -> Unit) {
mOnCheckedChangeListener = object: OnCheckedChangeListener {
override fun onCheckedChanged(buttonView: ImageToggleButton, isChecked: Boolean) {
callback(buttonView, isChecked)
}
}
}
/**
* Interface definition for a callback to be invoked when the checked state
* of a compound button changed.
*/
interface OnCheckedChangeListener {
/**
* Called when the checked state of a compound button has changed.
* @param buttonView The compound button view whose state has changed.
* *
* @param isChecked The new checked state of buttonView.
*/
fun onCheckedChanged(buttonView: ImageToggleButton, isChecked: Boolean)
}
override fun getAccessibilityClassName(): CharSequence {
return ImageToggleButton::class.java.name
}
// Saving view state
internal class SavedState : View.BaseSavedState {
var checked: Boolean = false
/**
* Constructor called from [CompoundButton.onSaveInstanceState]
*/
constructor(superState: Parcelable) : super(superState)
/**
* Constructor called from [.CREATOR]
*/
private constructor(parcel: Parcel) : super(parcel) {
checked = parcel.readValue(null) as Boolean
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeValue(checked)
}
override fun toString(): String {
return "CompoundButton.SavedState{${Integer.toHexString(System.identityHashCode(this))} checked= $checked }"
}
companion object {
val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(`in`: Parcel): SavedState {
return SavedState(`in`)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
}
public override fun onSaveInstanceState(): Parcelable {
val superState = super.onSaveInstanceState()
val ss = SavedState(superState)
ss.checked = isChecked
return ss
}
public override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.getSuperState())
isChecked = ss.checked
requestLayout()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_codes)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
//Listen for changes in the back stack
supportFragmentManager.addOnBackStackChangedListener(this)
//Handle when activity is recreated like on orientation Change
shouldDisplayHomeUp()
if (savedInstanceState == null) {
//Подготавливаю фрагмент
supportFragmentManager
.beginTransaction()
.add(R.id.container, GalleryFolderFragment())
.addToBackStack(null)
.commit()
}
}
override fun onSupportNavigateUp(): Boolean {
//This method is called when the up button is pressed. Just the pop back stack.
if (supportFragmentManager.backStackEntryCount > 1) {
supportFragmentManager.popBackStack()
} else {
onBackPressed()
}
return true
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 1) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
super.onBackPressed()
}
override fun onBackStackChanged() {
shouldDisplayHomeUp()
}
fun shouldDisplayHomeUp() {
//Enable Up button only if there are entries in the back stack
val canBack = supportFragmentManager.backStackEntryCount > 0
supportActionBar?.setDisplayHomeAsUpEnabled(canBack)
}
// Transparent button's background
android:background="?android:attr/selectableItemBackground"
// Consider using compound drawable to text views
<TextView
android:drawableLeft
android:drawableTop
android:drawableRight
android:drawableBottom
/>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="2.0dp"/>
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<solid android:color="@color/colorBackground"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="2.0dp"/>
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<solid android:color="@color/colorBackgroundDark"/>
</shape>
</item>
</selector>