Toggle linear layout - android

I need to create a complex toggle button (rtl checkbox).
I know that LinearLayout can be clickable, and I saw the following example
Can I do it through XML only?

Checkboxes and other views should be directly swapped when using rtl locales.
If you want to make sure you are compliant with RTL languages use the new "start" & "end" params included in JellyBean (marginStart & marginEnd instead of marginLeft/Right & marginRight/Left). Although if you need that behavior for previous versions you might need other tricks.
Note that TextView's will already move completely to the other side of the box: make sure you don't use a lot of WRAP_CONTENT in that case, it may result in misalignments.

LinearLayout can be clickable but not not checkable.
To get RTL toggle view I did the following:
I created a nine-path images to pressed, checked and default state.
Created a selector:
<item android:drawable="#drawable/button1_on" android:state_pressed="true"/>
<item android:drawable="#drawable/button1_selected" android:state_checked="true"/>
<item android:drawable="#drawable/button1_off"/>
3.Created a class that extends Button and Implements Checkable:
public class MyCheckbox extends Button implements Checkable {
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
private boolean mIsChecked = false;
public MyCheckbox(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyCheckbox(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyCheckbox(Context context) {
super(context);
}
#Override
public boolean isChecked() {
return mIsChecked;
}
#Override
public void setChecked(boolean isChecked) {
mIsChecked = isChecked;
}
#Override
public void toggle() {
setChecked(!mIsChecked);
}
#Override
public boolean performClick() {
toggle();
return super.performClick();
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
In the same way it can be implemented on a clickable LinearLayout

Related

VisibilityAwareImageButton Usage

I was recently working with ImageButtons and I came across this new type of ImageButton 'VisibilityAwareImageButton'. It would be really helpful if someone could tell me the usage of this ImageButton and how is it different from the regular ImageButton? Thanks in advance :)
Here's the full source for VisibilityAwareImageButton.
class VisibilityAwareImageButton extends ImageButton {
private int mUserSetVisibility;
public VisibilityAwareImageButton(Context context) {
this(context, null);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mUserSetVisibility = getVisibility();
}
#Override
public void setVisibility(int visibility) {
internalSetVisibility(visibility, true);
}
final void internalSetVisibility(int visibility, boolean fromUser) {
super.setVisibility(visibility);
if (fromUser) {
mUserSetVisibility = visibility;
}
}
final int getUserSetVisibility() {
return mUserSetVisibility;
}
}
It appears to be almost exactly the same as a regular ImageButton, only it keeps track of the last visibility actually set by the user. The only usage I can find is in the FloatingActionButton source. It is used to keep track of what the user wants the visibility of the view to be while it does it's own internal changes and animations. i.e.
if (child.getUserSetVisibility() != VISIBLE) {
// The view isn't set to be visible so skip changing it's visibility
return false;
}
It's in the design support library and has package visibility, so it seems like Google intends on using it internally (and seemingly only for the FAB implementation at this time).

There is a way to start contentScrim animation sooner on CollapsingToolbarLayout?

In this example the contentScrim attribute is set with a color, but I can't figure out how to control when it starts. I woud like to start the color transition sooner.
Can you give me a hint? Thanks in advance.
You'd have to create a class that extends CollapsingToolbarLayout. Something like this (you might need to adjust that so it exactly fits your needs):
public class CustomCollapsingToolbarLayout extends CollapsingToolbarLayout {
public static interface Listener {
public void onContentScrimAnimationStarted(boolean showing);
}
private Listener mListener;
public CustomCollapsingToolbarLayout(Context context) {
super(context);
}
public CustomCollapsingToolbarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomCollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setScrimsShown(boolean shown, boolean animate) {
super.setScrimsShown(shown, animate);
if (animate && mListener != null) {
mListener.onContentScrimAnimationStarted(shown);
}
}
public void setListener(Listener listener) {
mListener = listener;
}
}
And just call setListener on your CustomCollapsingToolbarLayout instance.
CustomCollapsingToolbarLayout mToolbarLayout =
(CustomCollapsingToolbarLayout) findViewById(R.id.toolbar_layout);
mToolbarLayout.setListener(new Listener() {
#Override
public void onContentScrimAnimationStarted(boolean showing) {
//do what you want
}
});
EDIT (actually answering the question):
Modify the scrimVisibleHeightTrigger value (with the setScrimVisibleHeightTrigger method of the CollapsingToolbarLayout) to change the starting point of the animation.

Common method or xml for Onclick changing of button color

I have around twenty custom buttons in my app, with a different image for each button.
I know that to create a click effect I have to create an XML resource like this, I have to created 20 different XML resources for my buttons.
Is there a better way to get the same result without creating separate XML resources for each button?
Update:
Can we make the button translucent when it is clicked.
Found the solution Here.
public class SAutoBgButton extends Button {
public SAutoBgButton(Context context) {
super(context);
}
public SAutoBgButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SAutoBgButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setBackgroundDrawable(Drawable d) {
// Replace the original background drawable (e.g. image) with a LayerDrawable that
// contains the original drawable.
SAutoBgButtonBackgroundDrawable layer = new SAutoBgButtonBackgroundDrawable(d);
super.setBackgroundDrawable(layer);
}
/**
* The stateful LayerDrawable used by this button.
*/
protected class SAutoBgButtonBackgroundDrawable extends LayerDrawable {
// The color filter to apply when the button is pressed
protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
// Alpha value when the button is disabled
protected int _disabledAlpha = 100;
public SAutoBgButtonBackgroundDrawable(Drawable d) {
super(new Drawable[] { d });
}
#Override
protected boolean onStateChange(int[] states) {
boolean enabled = false;
boolean pressed = false;
for (int state : states) {
if (state == android.R.attr.state_enabled)
enabled = true;
else if (state == android.R.attr.state_pressed)
pressed = true;
}
mutate();
if (enabled && pressed) {
setColorFilter(_pressedFilter);
} else if (!enabled) {
setColorFilter(null);
setAlpha(_disabledAlpha);
} else {
setColorFilter(null);
}
invalidateSelf();
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}
}
Use this in xml:
<net.shikii.widgets.SAutoBgButton
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="#drawable/button_blue_bg"
android:text="Button with background image" />

How to move buttons text when state is pressed

I made a custom background for a button and also for different button states. But now I made to a point that I cannot understand.
When button is in normal state then it looks just fine. But when I press the button, I need to move text down few pixels because button background image moving (actually it feels like it moving on the image, because first there's border under the button and when it's in pressed state then this border disappears). Please see image below.
How can I move the buttons text in the button when buttons state is pressed? (maybe padding somehow or layout custom for a button)
Setting padding in 9-patch didn't work for me.
Setting padding in touch listeners is messy, would litter code anywhere buttons are used.
I went with subclassing Button, and it turned out reasonably tidy. In my case, I wanted to offset icon (drawableLeft) and text 1px left and 1px down.
Subclassed button widget:
package com.myapp.widgets;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
import com.myapp.R;
public class OffsetButton extends Button {
public OffsetButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public OffsetButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OffsetButton(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean value = super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
setBackgroundResource(R.drawable.btn_normal);
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
setBackgroundResource(R.drawable.btn_pressed);
setPadding(getPaddingLeft() + 1, getPaddingTop() + 1, getPaddingRight() - 1,
getPaddingBottom() - 1);
}
return value;
}
}
And use it in layout like this:
<com.myapp.widgets.OffsetButton
android:text="#string/click_me"
android:drawableLeft="#drawable/icon_will_be_offset_too_thats_good" />
Few notes:
I did not use StateListDrawable for background, and am instead switching backgrounds in code. When I tried using StateListDrawable, there would be small pause between padding change and background change. That didn't look good.
Setting background resets padding, so don't need to adjust padding in ACTION_UP case
It was important to increase top and left padding, and at the same time decrease bottom and right padding. So the size of content area stays the same and content area is effectively just shifted.
I did not try it myself but if you use nine-patch as a background drawable for both states then you should consider setting proper padding box in pressed state drawable. See details here.
You can use padding on the view. You can add an OnTouchListener to the button or view like
viewF.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction == MotionEvent.ACTION_UP) {
//set your padding
} else if (event.getAction == MotionEvent.ACTION_DOWN){
//set your padding
}
return true;
}
});
The ontouchlistener will let your know when the button is pressed and not.
The PÄ“teris Caune answer works worse than overriding setPressed(). But everithing OK with setPressed until you test your app at ICS or lower device and add button as listview item.
To archieve this I've improved my button's class:
public class OffsetButton extends Button {
private static final int OFFSET_IN_DP = 6;
private int offset_in_px;
private boolean wasPressed = false;
private Integer[] defaultPaddings;
public OffsetButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
public OffsetButton(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public OffsetButton(Context context) {
super(context);
initView();
}
private void initView() {
offset_in_px = (int) DisplayUtil.convertDpToPixel(OFFSET_IN_DP);
}
#Override
public void setPressed(boolean pressed) {
if (pressed && !wasPressed) {
changePaddings();
}
if (!pressed && wasPressed) {
resetPaddings();
}
super.setPressed(pressed);
}
private void changePaddings() {
defaultPaddings = new Integer[]{getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom()};
setPadding(getPaddingLeft(), getPaddingTop() + offset_in_px, getPaddingRight(), getPaddingBottom() - offset_in_px);
wasPressed = true;
}
private void resetPaddings() {
setPadding(defaultPaddings[0], defaultPaddings[1], defaultPaddings[2], defaultPaddings[3]);
wasPressed = false;
}
#Override
public boolean performClick() {
resetPaddings();
return super.performClick();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (isEnabled())
{
if (event.getAction() == MotionEvent.ACTION_DOWN && !wasPressed) {
changePaddings();
} else if (event.getAction() == MotionEvent.ACTION_UP && wasPressed) {
resetPaddings();
}
}
return super.onTouchEvent(event);
}
}
this might just work:
setPadding(left, top, right, bottom); // Normal
setPadding(left, top + x, right, bottom - x); // Pressed

Prevent ToggleButton from switching state

I have a ToggleButton, when you click it, I don't want the state to change. I will handle state changes myself when after I receive feedback from whatever the button toggled. How might I prevent the state change on click?
You can implement your own ToggleButton with overriden toggle() method with empty body.
You could simply use the CheckedTextView instead.
Of course, you need to set a background image and a text based on the state, but other than those (which you might have used already), it's a nice alternative solution.
here's a sample code in case you miss the textOn and textOff attributes:
CheckableTextView.java :
public class CheckableTextView extends CheckedTextView {
private CharSequence mTextOn, mTextOff;
public CheckableTextView (final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckableTextView, defStyle, 0);
mTextOn = a.getString(R.styleable.CheckableTextView_textOn);
mTextOff = a.getString(R.styleable.CheckableTextView_textOff);
a.recycle();
}
public CheckableTextView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public CheckableTextView(final Context context) {
this(context, null, 0);
}
#Override
public void setChecked(final boolean checked) {
super.setChecked(checked);
if (mTextOn == null && mTextOff == null)
return;
if (checked)
super.setText(mTextOn);
else
super.setText(mTextOff);
}
public void setTextOff(final CharSequence textOff) {
this.mTextOff = textOff;
}
public void setTextOn(final CharSequence textOn) {
this.mTextOn = textOn;
}
public CharSequence getTextOff() {
return this.mTextOff;
}
public CharSequence getTextOn() {
return this.mTextOn;
}
}
in res/values/attr.xml :
<declare-styleable name="SyncMeCheckableTextView">
<attr name="textOn" format="reference|string" />
<attr name="textOff" format="reference|string" />
</declare-styleable>
another possible solution would be to use setClickable(false) on the ToggleButton, and handle onTouchListener when the motion action is ACTION_UP .
While I think you can just mark it as disabled, I don't think it is a good idea, as users are used to a certain semantic of such a button.
If you only want to show some state, why don't you use an ImageView and show different images depending on state?

Categories

Resources