+ * If the radio button is already checked, this method will not toggle the radio button. + */ + @Override + public void toggle() { + // we override to prevent toggle when the radio is already + // checked (as opposed to check boxes widgets) + if (!isChecked()) { + setChecked(!mChecked); + } + } + + @Override + public boolean performClick() { + /* + * XXX: These are tiny, need some surrounding 'expanded touch area', + * which will need to be implemented in Button if we only override + * performClick() + */ + + /* When clicked, toggle the state */ + toggle(); + return super.performClick(); + } + + @ViewDebug.ExportedProperty + public boolean isChecked() { + return mChecked; + } + + /** + *
Changes the checked state of this button.
+ * + * @param checked true to check the button, false to uncheck it + */ + public void setChecked(boolean checked) { + if (mChecked != checked) { + mChecked = checked; + refreshDrawableState(); + compoundButton.setChecked(checked); + + // Avoid infinite recursions if setChecked() is called from a listener + if (mBroadcasting) { + return; + } + + mBroadcasting = true; + if (mOnCheckedChangeListener != null) { + mOnCheckedChangeListener.onCheckedChanged(compoundButton, mChecked); + } + + + mBroadcasting = false; + } + } + + /** + * Register a callback to be invoked when the checked state of this button + * changes. + * + * @param listener the callback to call on checked state change + */ + public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener listener) { + mOnCheckedChangeListener = listener; + } + + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(CustomizableRadioButton.class.getName()); + event.setChecked(mChecked); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(CustomizableRadioButton.class.getName()); + info.setCheckable(true); + info.setChecked(mChecked); + } + + private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked}; + + @Override + protected int[] onCreateDrawableState(int extraSpace) { + final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); + if (isChecked()) { + mergeDrawableStates(drawableState, CHECKED_STATE_SET); + } + return drawableState; + } + + + static class SavedState extends BaseSavedState { + boolean checked; + + /** + * Constructor called from {@link CompoundButton#onSaveInstanceState()} + */ + SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + checked = (Boolean) in.readValue(null); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeValue(checked); + } + + @Override + public String toString() { + return "CompoundButton.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " checked=" + checked + "}"; + } + + public static final CreatorSets the selection to the radio button whose identifier is passed in + * parameter. Using -1 as the selection identifier clears the selection; + * such an operation is equivalent to invoking {@link #clearCheck()}.
+ * + * @param id the unique id of the radio button to select in this group + * @see #getCheckedRadioButtonId() + * @see #clearCheck() + */ + public void check(int id) { + // don't even bother + if (id != -1 && (id == mCheckedId)) { + return; + } + + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + + if (id != -1) { + setCheckedStateForView(id, true); + } + + setCheckedId(id); + } + + private void setCheckedId(int id) { + mCheckedId = id; + if (mOnCheckedChangeListener != null) { + mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId); + } + } + + private void setCheckedStateForView(int viewId, boolean checked) { + View checkedView = findViewById(viewId); + if (checkedView != null && checkedView instanceof RadioButton) { + ((RadioButton) checkedView).setChecked(checked); + } + } + + /** + *Returns the identifier of the selected radio button in this group. + * Upon empty selection, the returned value is -1.
+ * + * @return the unique id of the selected radio button in this group + * @attr ref android.R.styleable#RadioGroup_checkedButton + * @see #check(int) + * @see #clearCheck() + */ + public int getCheckedRadioButtonId() { + return mCheckedId; + } + + /** + *Clears the selection. When the selection is cleared, no radio button + * in this group is selected and {@link #getCheckedRadioButtonId()} returns + * null.
+ * + * @see #check(int) + * @see #getCheckedRadioButtonId() + */ + public void clearCheck() { + check(-1); + } + + /** + *Register a callback to be invoked when the checked radio button + * changes in this group.
+ * + * @param listener the callback to call on checked state change + */ + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + mOnCheckedChangeListener = listener; + } + + /** + * {@inheritDoc} + */ +// @Override +// public FlexBoxRadioGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { +// return new FlexBoxRadioGroup.LayoutParams(getContext(), attrs); +// } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof RadioGroup.LayoutParams; + } + + @Override + protected FlexboxLayout.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(RadioGroup.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(RadioGroup.class.getName()); + } + + /** + *This set of layout parameters defaults the width and the height of + * the children to {@link #WRAP_CONTENT} when they are not specified in the + * XML file. Otherwise, this class uses the value read from the XML file.
+ */ + public static class LayoutParams extends FlexboxLayout.LayoutParams { + /** + * {@inheritDoc} + */ + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int w, int h) { + super(w, h); + } + +// /** +// * {@inheritDoc} +// */ +// public LayoutParams(int w, int h, float initWeight) { +// super(w, h, initWeight); +// } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.LayoutParams p) { + super(p); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(MarginLayoutParams source) { + super(source); + } + + /** + *Fixes the child's width to + * {@link ViewGroup.LayoutParams#WRAP_CONTENT} and the child's + * height to {@link ViewGroup.LayoutParams#WRAP_CONTENT} + * when not specified in the XML file.
+ * + * @param a the styled attributes set + * @param widthAttr the width attribute to fetch + * @param heightAttr the height attribute to fetch + */ + @Override + protected void setBaseAttributes(TypedArray a, + int widthAttr, int heightAttr) { + + if (a.hasValue(widthAttr)) { + width = a.getLayoutDimension(widthAttr, "layout_width"); + } else { + width = WRAP_CONTENT; + } + + if (a.hasValue(heightAttr)) { + height = a.getLayoutDimension(heightAttr, "layout_height"); + } else { + height = WRAP_CONTENT; + } + } + } + + /** + *Interface definition for a callback to be invoked when the checked + * radio button changed in this group.
+ */ + public interface OnCheckedChangeListener { + /** + *Called when the checked radio button has changed. When the + * selection is cleared, checkedId is -1.
+ * + * @param group the group in which the checked radio button has changed + * @param checkedId the unique identifier of the newly checked radio button + */ + void onCheckedChanged(FlexBoxRadioGroup group, int checkedId); + } + + private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + // prevents from infinite recursion + if (mProtectFromCheckedChange) { + return; + } + + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + + int id = buttonView.getId(); + setCheckedId(id); + } + } + + /** + *A pass-through listener acts upon the events and dispatches them + * to another listener. This allows the table layout to set its own internal + * hierarchy change listener without preventing the user to setup his.
+ */ + private class PassThroughHierarchyChangeListener implements + OnHierarchyChangeListener { + private OnHierarchyChangeListener mOnHierarchyChangeListener; + + /** + * {@inheritDoc} + */ + public void onChildViewAdded(View parent, View child) { + if (parent == FlexBoxRadioGroup.this && child instanceof RadioButton) { + int id = child.getId(); + // generates an id if it's missing + if (id == View.NO_ID) { + id = child.hashCode(); + child.setId(id); + } + ((RadioButton) child).setOnCheckedChangeListener( + mChildOnCheckedChangeListener); + } + + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewAdded(parent, child); + } + } + + /** + * {@inheritDoc} + */ + public void onChildViewRemoved(View parent, View child) { + if (parent == FlexBoxRadioGroup.this && child instanceof RadioButton) { + ((RadioButton) child).setOnCheckedChangeListener(null); + } + + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewRemoved(parent, child); + } + } + } +} \ No newline at end of file diff --git a/OneToOne/src/main/java/com/shayu/onetoone/widget/flexboxradiogroup/FlexBoxSingleCheckableGroup.java b/OneToOne/src/main/java/com/shayu/onetoone/widget/flexboxradiogroup/FlexBoxSingleCheckableGroup.java new file mode 100644 index 000000000..f67ac0b11 --- /dev/null +++ b/OneToOne/src/main/java/com/shayu/onetoone/widget/flexboxradiogroup/FlexBoxSingleCheckableGroup.java @@ -0,0 +1,396 @@ +package com.shayu.onetoone.widget.flexboxradiogroup; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Checkable; +import android.widget.CompoundButton; + +import android.widget.RadioButton; +import android.widget.RadioGroup; + +import com.google.android.flexbox.FlexDirection; +import com.google.android.flexbox.FlexboxLayout; +import com.shayu.onetoone.R; + +import java.lang.reflect.Method; + + +public class FlexBoxSingleCheckableGroup extends FlexboxLayout { + + private static final String TAG = "FlexBoxSingleCheckableG"; + // holds the checked id; the selection is empty by default + private int mCheckedId = -1; + // tracks children radio buttons checked state + private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener; + // when true, mOnCheckedChangeListener discards events + private boolean mProtectFromCheckedChange = false; + private OnCheckedChangeListener mOnCheckedChangeListener; + private PassThroughHierarchyChangeListener mPassThroughListener; + + /** + * {@inheritDoc} + */ + public FlexBoxSingleCheckableGroup(Context context) { + super(context); + setFlexDirection(FlexDirection.ROW); + init(); + } + + /** + * {@inheritDoc} + */ + public FlexBoxSingleCheckableGroup(Context context, AttributeSet attrs) { + super(context, attrs); + + // retrieve selected radio button as requested by the user in the + // XML layout file + TypedArray attributes = context.obtainStyledAttributes( + attrs, R.styleable.FlexBoxRadioGroup); + + int value = attributes.getResourceId(R.styleable.FlexBoxRadioGroup_uiCheckedButton, View.NO_ID); + if (value != View.NO_ID) { + mCheckedId = value; + } + + attributes.recycle(); + init(); + } + + private void init() { + mChildOnCheckedChangeListener = new CheckedStateTracker(); + mPassThroughListener = new PassThroughHierarchyChangeListener(); + super.setOnHierarchyChangeListener(mPassThroughListener); + } + + /** + * {@inheritDoc} + */ + @Override + public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) { + // the user listener is delegated to our pass-through listener + mPassThroughListener.mOnHierarchyChangeListener = listener; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + // checks the appropriate radio button as requested in the XML file + if (mCheckedId != -1) { + mProtectFromCheckedChange = true; + setCheckedStateForView(mCheckedId, true); + mProtectFromCheckedChange = false; + setCheckedId(mCheckedId); + } + } + + + public void addView(View child, int index, ViewGroup.LayoutParams params, boolean isChecked) { + if (child instanceof Checkable) { + + if (isChecked) { + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + setCheckedId(child.getId()); + } + } + + super.addView(child, index, params); +// if (child instanceof RadioButton) { +// final RadioButton button = (RadioButton) child; +// if (button.isChecked()) { +// mProtectFromCheckedChange = true; +// if (mCheckedId != -1) { +// setCheckedStateForView(mCheckedId, false); +// } +// mProtectFromCheckedChange = false; +// setCheckedId(button.getId()); +// } +// } +// +// super.addView(child, index, params); + } + + /** + *Sets the selection to the radio button whose identifier is passed in + * parameter. Using -1 as the selection identifier clears the selection; + * such an operation is equivalent to invoking {@link #clearCheck()}.
+ * + * @param id the unique id of the radio button to select in this group + * @see #getCheckedRadioButtonId() + * @see #clearCheck() + */ + public void check(int id) { + // don't even bother + if (id != -1 && (id == mCheckedId)) { + return; + } + + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + + if (id != -1) { + setCheckedStateForView(id, true); + } + + setCheckedId(id); + } + + private void setCheckedId(int id) { + mCheckedId = id; + if (mOnCheckedChangeListener != null) { + mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId); + } + } + + private void setCheckedStateForView(int viewId, boolean checked) { + View checkedView = findViewById(viewId); + if (checkedView != null && checkedView instanceof Checkable) { + try { + Method m = checkedView.getClass() + .getMethod("setChecked", boolean.class); + m.invoke(checkedView, checked); + } catch (Exception e) { + Log.e(TAG, ""); + } + } + } + + /** + *Returns the identifier of the selected radio button in this group. + * Upon empty selection, the returned value is -1.
+ * + * @return the unique id of the selected radio button in this group + * @attr ref android.R.styleable#RadioGroup_checkedButton + * @see #check(int) + * @see #clearCheck() + */ + public int getCheckedRadioButtonId() { + return mCheckedId; + } + + /** + *Clears the selection. When the selection is cleared, no radio button + * in this group is selected and {@link #getCheckedRadioButtonId()} returns + * null.
+ * + * @see #check(int) + * @see #getCheckedRadioButtonId() + */ + public void clearCheck() { + check(-1); + } + + /** + *Register a callback to be invoked when the checked radio button + * changes in this group.
+ * + * @param listener the callback to call on checked state change + */ + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + mOnCheckedChangeListener = listener; + } + + /** + * {@inheritDoc} + */ +// @Override +// public FlexBoxRadioGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { +// return new FlexBoxRadioGroup.LayoutParams(getContext(), attrs); +// } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof RadioGroup.LayoutParams; + } + + @Override + protected FlexboxLayout.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(RadioGroup.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(RadioGroup.class.getName()); + } + + /** + *This set of layout parameters defaults the width and the height of + * the children to {@link #WRAP_CONTENT} when they are not specified in the + * XML file. Otherwise, this class uses the value read from the XML file.
+ */ + public static class LayoutParams extends FlexboxLayout.LayoutParams { + /** + * {@inheritDoc} + */ + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int w, int h) { + super(w, h); + } + +// /** +// * {@inheritDoc} +// */ +// public LayoutParams(int w, int h, float initWeight) { +// super(w, h, initWeight); +// } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.LayoutParams p) { + super(p); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(MarginLayoutParams source) { + super(source); + } + + /** + *Fixes the child's width to + * {@link ViewGroup.LayoutParams#WRAP_CONTENT} and the child's + * height to {@link ViewGroup.LayoutParams#WRAP_CONTENT} + * when not specified in the XML file.
+ * + * @param a the styled attributes set + * @param widthAttr the width attribute to fetch + * @param heightAttr the height attribute to fetch + */ + @Override + protected void setBaseAttributes(TypedArray a, + int widthAttr, int heightAttr) { + + if (a.hasValue(widthAttr)) { + width = a.getLayoutDimension(widthAttr, "layout_width"); + } else { + width = WRAP_CONTENT; + } + + if (a.hasValue(heightAttr)) { + height = a.getLayoutDimension(heightAttr, "layout_height"); + } else { + height = WRAP_CONTENT; + } + } + } + + /** + *Interface definition for a callback to be invoked when the checked + * radio button changed in this group.
+ */ + public interface OnCheckedChangeListener { + /** + *Called when the checked radio button has changed. When the + * selection is cleared, checkedId is -1.
+ * + * @param group the group in which the checked radio button has changed + * @param checkedId the unique identifier of the newly checked radio button + */ + void onCheckedChanged(FlexBoxSingleCheckableGroup group, int checkedId); + } + + private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + // prevents from infinite recursion + if (mProtectFromCheckedChange) { + return; + } + + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + + int id = buttonView.getId(); + setCheckedId(id); + } + } + + /** + *A pass-through listener acts upon the events and dispatches them + * to another listener. This allows the table layout to set its own internal + * hierarchy change listener without preventing the user to setup his.
+ */ + private class PassThroughHierarchyChangeListener implements + OnHierarchyChangeListener { + private OnHierarchyChangeListener mOnHierarchyChangeListener; + + /** + * {@inheritDoc} + */ + public void onChildViewAdded(View parent, View child) { + if (parent == FlexBoxSingleCheckableGroup.this && child instanceof Checkable) { + int id = child.getId(); + // generates an id if it's missing + if (id == View.NO_ID) { + id = child.hashCode(); + child.setId(id); + } + try { + Method m = child.getClass() + .getMethod("setOnCheckedChangeListener", CompoundButton.OnCheckedChangeListener.class); + m.invoke(child, mChildOnCheckedChangeListener); + } catch (Exception e) { + Log.e(TAG, ""); + } + } + + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewAdded(parent, child); + } + } + + /** + * {@inheritDoc} + */ + public void onChildViewRemoved(View parent, View child) { + if (parent == FlexBoxSingleCheckableGroup.this && child instanceof Checkable) { + ((RadioButton) child).setOnCheckedChangeListener(null); + try { + Method m = child.getClass() + .getMethod("setOnCheckedChangeListener", CompoundButton.OnCheckedChangeListener.class); + m.invoke(child, (Object[]) null); + } catch (Exception e) { + Log.e(TAG, ""); + } + } + + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewRemoved(parent, child); + } + } + } +} \ No newline at end of file diff --git a/OneToOne/src/main/res/drawable/bg_home_search_btn.xml b/OneToOne/src/main/res/drawable/bg_home_search_btn.xml new file mode 100644 index 000000000..09a9ef524 --- /dev/null +++ b/OneToOne/src/main/res/drawable/bg_home_search_btn.xml @@ -0,0 +1,5 @@ + +