How to create custom Android radio buttons? - java

I've got a couple radio button options in my android app, but I want them to look totally different. More something like below (quick mockup) in which you simply click the words you want and it makes them bold and underlined.
Does anybody know how I can achieve something like this? All tips are welcome!

Generally speaking, to override the look of default widgets, you'll need to create a drawable folder and put all of your xml definitions in that folder. Then reference that xml file within the RadioButton block of your layout.
Here's a good blog post on how to do all that:
http://blog.devminded.com/posts/custom-android-radiobutton

I know it might be late, but it is not a reason to keep the solution for myself.
1) You need to implement the .XML layout for the RadioGroup and it's RadioButtons. Set the RadioGroup children orientation with Horizontal value to display the button side by side. Setting the RadioButton button with #null value to hide the default selector
As following:
<RadioGroup
android:id="#+id/my_radiogroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="#+id/i_like_radiobutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="#null"
android:padding="10dp"
android:text="I Like"
android:textColor="#android:color/holo_orange_light" />
<RadioButton
android:id="#+id/i_dont_like_radiobutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="#null"
android:padding="10dp"
android:text="I Dont Like"
android:textColor="#android:color/holo_orange_light" />
</RadioGroup>
2) In your Activity class, initialize them and set their listener. The listener should keep track of the changes of the RadioButton changes and set the UI changes according to the state either select or unselect. As following:
RadioGroup myRadioGroup = (RadioGroup) findViewById(R.id.my_radiogroup);
RadioButton likeRadioButton = (RadioButton) findViewById(R.id.i_like_radiobutton);
RadioButton dontLikeRadioButton = (RadioButton) findViewById(R.id.i_dont_like_radiobutton);
//Like button listener
likeRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//Make the text underlined
SpannableString content = new SpannableString(getString(R.string.like_text));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
buttonView.setText(content);
//Make the text BOLD
buttonView.setTypeface(null, Typeface.BOLD);
} else {
//Change the color here and make the Text bold
SpannableString content = new SpannableString(getString(R.string.like_text));
content.setSpan(null, 0, content.length(), 0);
buttonView.setText(content);
buttonView.setTypeface(null, Typeface.NORMAL);
}
}
});
//Don't Like button listener
dontLikeRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//Change the color here and make the Text bold
SpannableString content = new SpannableString(getString(R.string.like_text));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
buttonView.setText(content);
buttonView.setTypeface(null, Typeface.BOLD);
} else {
//Change the color here and make the Text bold
SpannableString content = new SpannableString(getString(R.string.like_text));
content.setSpan(null, 0, content.length(), 0);
buttonView.setText(content);
buttonView.setTypeface(null, Typeface.NORMAL);
}
}
});
3) Now, the RadioButton will change it's color and it's TextStyle according to it's state automatically. You can add more customization if you want.
4) For performing the required action when the user select any of the Buttons, we need to override the setOnCheckedChangeListener method for the RadioGroup as following:
genderRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.i_dont_like_radiobutton) {
//Do some actions
} else if (checkedId == R.id.i_like_radiobutton){
}
}
});
The final output will be very similar the the question image except the separator.
I hope it helps.

Related

Android Material Button Toggle Group

I'm creating a form in android which asks for gender. To get this input I use Material Button Toggle Group which contains two buttons. I don't know how to know which button is clicked in my activity.java. How to get to know about the selected button in my activity so that i can save the details in different database.
myxml.xml
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="#+id/toggleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:singleSelection="true">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Male"
android:layout_marginStart="5dp"
style="?attr/materialButtonOutlinedStyle"/>
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Female"
android:layout_marginStart="10dp"
style="?attr/materialButtonOutlinedStyle"/>
</com.google.android.material.button.MaterialButtonToggleGroup>
Myactivity.java
MaterialButtonToggleGroup toggleButton = findViewById(R.id.toggleButton);
toggleButton.addOnButtonCheckedListener();
// I CAN'T FIND ANY PROPER SOLUTION
You can use the getCheckedButtonId() method.
Something like:
MaterialButtonToggleGroup materialButtonToggleGroup =
findViewById(R.id.toggleButton);
int buttonId = materialButtonToggleGroup.getCheckedButtonId();
MaterialButton button = materialButtonToggleGroup.findViewById(buttonId);
Only if you need a listener you can use the addOnButtonCheckedListener:
materialButtonToggleGroup.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() {
#Override
public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) {
if (isChecked) {
if (checkedId == R.id.button1) {
//..
}
}
}
});
You have to check the checkedId value but also the isChecked value. The same listener is called when you check a button but also when you unckeck a button.
It means that if you click the button1 the listener is called with isChecked=true and checkedId=1. Then if you click the button2 the listener is called twice. Once with isChecked=false and checkedId=1, once with isChecked=true and checkedId=2.
You can do it like this :
toggleButton.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() {
#Override
public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) {
if(group.getCheckedButtonId()==R.id.button1)
{
//Place code related to button1 here
Toast.makeText(MainActivity2.this, "Button1 Clicked", Toast.LENGTH_SHORT).show();
}else if(group.getCheckedButtonId()==R.id.button2) {
//Place code related to button 2 here
Toast.makeText(MainActivity2.this, "Button2 Clicked", Toast.LENGTH_SHORT).show();
}
}
});

How click to part of string of TextView in InputTextLayout (error or help message)

It's a solved problem, but I want to share my solution with community.
I use a component TextInputLayout with EditText inside.
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textInputLayout"
style="#style/Widget.MaterialComponents.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/emailEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"/>
</com.google.android.material.textfield.TextInputLayout>
When I need to show error I use this method:
textInputLayout.setErrorEnabled(true);
textInputLayout.setError(errorMessage);
But in my case I need to show a button in a message inside errorMessage with another color and clickable.
For example my message:
User with this email already exist. Sign in
I need a clickable, bold text style Sign in in this message.
I used SpannableStringBuilder, changed color and created listener, but click event didn't work. And I couldn'd use method
TextView.setMovementMethod(LinkMovementMethod.getInstance());
for TextInputLayout or TextInputEditText.
After many hours to be trying to solve this case I found a some way, which works for me. I got a TextView from TextInputLayout by this:
((TextView)((FrameLayout)((LinearLayout) til.getChildAt(1)).getChildAt(0)).getChildAt(0))
.setMovementMethod(LinkMovementMethod.getInstance());
All code for creating part of message clickable in InputTextLayout:
textInputLayout.setErrorEnabled(true);
String text = getString("User with this email already exist. Sign in");
SpannableStringBuilder ssBuilder = new SpannableStringBuilder(text);
int startPoint = text.indexOf("Sign in");
int endPoint = text.indexOf("Sign in") + String.valueOf("Sign in").length();
int flags = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
ssBuilder.setSpan(new ClickableSpan() {
#Override
public void onClick(#NonNull View widget) {
//put your code here...
widget.invalidate(); //for hide background shadow after click
}
#Override
public void updateDrawState(#NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
ds.setFakeBoldText(true);
ds.setColor(getResources().getColor(R.color.colorWhite));
}
}, startPoint, endPoint, flags);
((TextView)((FrameLayout)((LinearLayout) textInputLayout.getChildAt(1)).getChildAt(0)).getChildAt(0))
.setMovementMethod(LinkMovementMethod.getInstance());
textInputLayout.setError(ssBuilder);
Thank you for your attention!
I think you should try creating a Material button button below
TextInputLayout with visibility set to hide as this will be an
easier solution instead of above solution that you have provided.
Whenever you want to show error as well as you can handle click on that button.

How to manage the position of TextViews dynamically when screen size changes

I have two textviews in one horizontal layout, the first is normal text and the second is clickable with a different color.
XML
<!--inside rootlayout..-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:maxLines="2"
android:text="By clicking sign up, you agree to our "
android:textColor="#color/black"
android:textSize="12sp"/>
<TextView
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="terms and conditions"
android:textColor="#color/colorPrimary"
android:textSize="12sp"
android:clickable="true"/>
</LinearLayout>
And It gives me a great look on large screens (4.7 inch and above),
but when the screen size is lower, the second textview gets weird.! I want it to automatically position itself below the first textview or to make their parent layout orientation vertical..!!
here's how it looks.!
Update #1
why the ForegroundColorSpan won't change!? it always shows blue or black no matter what color resources I set.!??
private void handleTermsConditions() {
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(termsTxt.getText());
stringBuilder.setSpan(new StyleSpan(Typeface.BOLD), 38, 58, 0);
int color = ContextCompat.getColor(RegistrationActivity.this, R.color.colorPrimary);
ForegroundColorSpan fcs = new ForegroundColorSpan(color);
stringBuilder.setSpan(fcs, termsTxt.getText().length() - 20, termsTxt.getText().length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View widget) {
Toast.makeText(RegistrationActivity.this, "Click", Toast.LENGTH_SHORT)
.show();
}
};
stringBuilder.setSpan(clickableSpan, 38, 58, Spanned.SPAN_POINT_MARK);
termsTxt.setMovementMethod(LinkMovementMethod.getInstance());
termsTxt.setText(stringBuilder);
}
The same question here or from the original document
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
Get the height and width of your device and use the values to decide whether to set screen to portrait or not:
if ((height == <value>) && (width == <value>)) {
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
*Feel free to modify as required in your activity
for your requirement you don't have to use 2 text views for this you can place a spannable string builder on just 1 text and put clickable as well as color property and you are done.
Code:
TextView textView = findViewById(R.id.tvSample);
SpannableStringBuilder stringBuilder =new SpannableStringBuilder(textView.getText());
stringBuilder.setSpan(new ForegroundColorSpan(Color.BLUE),textView.getText().length()-20,textView.getText().length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.setSpan(new ClickableSpan() {
#Override
public void onClick(final View view) {
Toast.makeText(MainActivity.this,"Click",Toast.LENGTH_LONG).show();
}
},textView.getText().length()-20,textView.getText().length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(stringBuilder);
Here is example of putting different spans on text view
This is how to set two spans on single text view
You can set TextView Font size or width according to screen size using value folder. Try like this.
You can use most easy way Android Spannable property for doing this. and by that way you can do this work by single textview and can manage your click events.
Here is code for doing this.
public void setHighLightedText(TextView textView, String textToHighlight) {
String tvt = textView.getText().toString();
int ofe = tvt.indexOf(textToHighlight, 0);
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
// here you do all stuff
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(0xff0000ff);
ds.setUnderlineText(true);
// Here you can put your style on textview.
}
};
SpannableString wordtoSpan = new SpannableString(textView.getText());
for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) {
ofe = tvt.indexOf(textToHighlight, ofs);
if (ofe == -1)
break;
else {
wordtoSpan.setSpan(clickableSpan, ofe, ofe + textToHighlight.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(wordtoSpan, TextView.BufferType.SPANNABLE);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
You can see onClick method in it. there you can set click or use callback if you put this code in Utility class.
Bonus
Also this is the right way to do this.
Either use Fragments
OR
Try autoSizeText
<TextView
.......
android:autoSizeTextType="uniform"
................................../>
Here is something about it on android developer site

disable checkboxes after certain number of checkboxes are checked

I have 6 checkboxes and I would want for example if I have a variable a=2 to let the user check 2 checkboxes and make the other disabled..if I have a=3 to let the user check 3 checkboxes and disable the rest and so on..This is what I tried:
public void itemClicked(View v) {
//code to check if this checkbox is checked!
CheckBox checkBox = (CheckBox)v;
check1=(CheckBox)findViewById(R.id.check1);
check2=(CheckBox)findViewById(R.id.check2);
check3=(CheckBox)findViewById(R.id.check3);
check4=(CheckBox)findViewById(R.id.check4);
check5=(CheckBox)findViewById(R.id.check5);
check6=(CheckBox)findViewById(R.id.check6);
if(a==1)
{
only one can be checked the others get disabled
}
}
}
and a part of the xml file is:
<CheckBox android:id="#+id/check1"
android:layout_width="140dp"
android:layout_height="250dp"
android:scaleX="1.0"
android:scaleY="1.0"
android:button="#layout/cb_selector"
android:layout_marginLeft="80dp"
android:layout_marginTop="505dp"
android:onClick="itemClicked"
/>
<CheckBox android:id="#+id/check2"
android:layout_width="140dp"
android:layout_height="250dp"
android:scaleX="1.0"
android:scaleY="1.0"
android:button="#layout/cb_selector"
android:layout_marginLeft="365dp"
android:layout_marginTop="505dp"
/>
How can I achive this?
You need an array of checkboxes and a your check of variable in onCheckedChange.
CheckBox[] cba;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cba = new CheckBox[]{
(CheckBox)findViewById(R.id.check1),
(CheckBox)findViewById(R.id.check2),
(CheckBox)findViewById(R.id.check3),
(CheckBox)findViewById(R.id.check4),
(CheckBox)findViewById(R.id.check5),
(CheckBox)findViewById(R.id.check6)
};
//here set onChechedChange for all your checkboxes
for (CheckBox cb:cba) {
cb.setOnCheckedChangeListener(cbListener);
}
}
CompoundButton.OnCheckedChangeListener cbListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkEnoughAndMakeDisabled(cba);
}
};
private void checkEnoughAndMakeDisabled(CheckBox checkBoxes[]){
int countChecked =0;
for (CheckBox cb:checkBoxes){
cb.setEnabled(true);
if (cb.isChecked()) countChecked++;
}
//your variable
if (a <= countChecked) {
for (CheckBox cb:checkBoxes){
if (!cb.isChecked())cb.setEnabled(false);
}
}
}
Ps: Also i think the best practice for such issues is usage of Data-Binding, but it is other story
If there's a case where the user can select only one option, you better use radio buttons.
Anyway, here's a good and simple answer: https://stackoverflow.com/a/20041237/5280641.

Android: Modifying Object's Fields With Its Own Click Listener

I have several radio buttons, each of which has a View.OnClickListener. The whole purpose of those listeners are for me to be able to change the color of the text associated with the RadioButton upon clicking this very RadioButton. My problem is, I'm not sure how to do that.
Here is how I set a listener for each RadioButton:
radioButton.setOnClickListener(badAnswerListener());
Here's the badAnswerListener method:
private View.OnClickListener badAnswerListener(){
return new View.OnClickListener() {
#Override
public void onClick(View arg0) {
//How do I change the radioButton's color?
}
};
}
If radioButton is private member of class :
radioButton.setTextColor(R.color.customcolor);
See this too, it's almost the same question :
Changing Text color of RadioButton if clicked in android
if you are only using radio button clicklistners to change the color of text.Have a look at the better approach.To change the text color when radio button is checked(clicked)
1) Use radio_text_selector.xml as below and put it into res/color folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#android:color/red" />
<item android:color="#504f4f" /> <--default case
</selector>
Use the above selector in "android:textColor" attribute like below
<RadioButton
android:id="#+id/radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/radio_text_selector" />
private View.OnClickListener badAnswerListener(){
return new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Change the clicked radioButton's text to red
((RadioButton) arg0).setTextColor(Color.RED);
}
};
}

Categories

Resources