I'm curious about how other people solve this problem:
When having an application which allows users to subscribe to each other, should you better use two buttons, one with a "Subscribe" text and the other with a "Unsubscribe" text or just use one button in the layout and change the text after clicking the button?
2 buttons solution
XML:
<Button
android:id="#+id/subscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Subscribe"
android:visibility="gone" />
<Button
android:id="#+id/unsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Unsubscribe"
android:visibility="gone" />
Java:
// update subscribe buttons
if (userProfile.getID() != user.getUserID()) {
if (userProfile.hasSubscribed()) {
unsubscribeView.setVisibility(View.VISIBLE);
}
else {
subscribeView.setVisibility(View.VISIBLE);
}
}
subscribeView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
subscribe = 1;
subscribe();
}
});
unsubscribeView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
subscribe = -1;
subscribe();
}
});
1 button solution
XML:
<Button
android:id="#+id/subscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
Java:
// update subscribe buttons
if (userProfile.getID() != user.getUserID()) {
if (userProfile.hasSubscribed()) {
subscribeView.setText("Unsubscribe");
}
else {
subscribeView.setText("Subscribe");
}
}
subscribeView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (userProfile.hasSubscribed()) {
subscribe = -1;
}
else {
subscribe = 1;
}
subscribe();
}
});
Use the one-button approach.
Try to keep the UI as clean as possible, and avoid having buttons that are visible, but don't have any effect.
Related
We have tried two ways to display a Custom Snackbar (1) as a masquerading Dialog which will not move to the bottom of the screen It does however not dismiss the current Activity view just makes it opaque. I know why it is in the center of the screen but I am not able to move it to the bottom. (2) next is a view that takes over the entire screen because it is a new content view that I am guessing dismisses the current Activity view BUT it is at the bottom of the screen.
So my question is how to use design number 1 and move the Dialog to the bottom of screen?
Second question how to stop the new view in design number 2 from dismissing the view of the current Activity? After careful reading and little thought and extreme testing I do not think this is possible! I have posted the code for my two methods below. The XML file uses a Relative Layout as the base container.
public void seeSB(){
setContentView(R.layout.custom_snackbar);
// Line of Code above shows XML file
// Line of code tested but no control over the "viewMyLayout"
//LayoutInflater inflater = LayoutInflater.from(ListActivity.this);
//final View viewMyLayout = inflater.inflate(R.layout.custom_snackbar, null);
//viewMyLayout.setEnabled(true);
Button btnAB = (Button) findViewById(R.id.btnAB);
btnAB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// viewMyLayout.setEnabled(false);
// Line above does not function
// CODE BELOW WORKS BUT FAR FROM elegant
setContentView(R.layout.activity_list);
//Intent intent = new Intent(ListActivity.this, ListActivity.class );
//startActivity(intent);
Toast.makeText(getApplicationContext(), "I WAS Clicked", Toast.LENGTH_SHORT).show();
}
});
}
public void displaySB(){
final Dialog openSnack = new Dialog(context);
openSnack.setContentView(R.layout.custom_snackbar);
Button btnAB = (Button)openSnack.findViewById(R.id.btnAB);
TextView tvSB =(TextView)openSnack.findViewById(R.id.tvSB);
//Dialog dialog = new Dialog(ListActivity.this);
//dialog.setContentView(Bottom);
// if YES delete Master Password from TABLE_MPW
btnAB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openSnack.dismiss();
Toast.makeText(getApplicationContext(), "I WAS Clicked", Toast.LENGTH_SHORT).show();
}
});
openSnack.show();
}
This is far from functional in my book because the method design has just one Custom Snackbar to look at so you need to work on how to have multiple fixed Custom Snackbars. One suggestion might be to have multiple sub views in your parent view and call the sub view you want. I will post just the sub view I added to the parent XML file and the not so real dynamic method to implement which is implemented in this case with a button click. For this to work in a real application the code would need be called from some method or event.
You might consider a switch statement for multiple views ? ? ?
TAKE NOTE THE RELATIVE LAYOUT has its visibility set to GONE at the start
<RelativeLayout
android:id="#+id/hold_snackbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/color_Black"
android:visibility="gone"
android:orientation="vertical">
<TextView
android:id="#+id/tvSB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:text="#string/snackbar_text"
android:textColor="#color/color_Yellow"
android:textSize="18sp"
android:textStyle="bold" />
<Button
android:id="#+id/btnAB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="350dp"
android:layout_marginTop="5dp"
android:background="#color/color_Transparent"
android:focusable="false"
android:text="#string/snackbar_action"
android:textColor="#color/color_Red"
android:textSize="18sp"
android:textStyle="bold" />
</RelativeLayout>
Notice the View subViewGroup is declared when the Activity starts
View subViewGroup;
public void makeSB(View view) {
subViewGroup = findViewById(R.id.hold_snackbar);
subViewGroup.setVisibility(View.VISIBLE);
seeSB();
}
public void seeSB(){
Button btnAB = (Button) findViewById(R.id.btnAB);
btnAB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
subViewGroup.setVisibility(View.GONE);
Toast.makeText(getApplicationContext(), "I WAS Clicked", Toast.LENGTH_SHORT).show();
}
});
}
Countdown Timer to close a Snackbar with no Action Button
public void makeCDT(View view) {
cdt = new CountDownTimer(5000, 100) {
// 5 sec 5000,100
// 10 sec 10000,100
#Override
public void onTick(long secsUntilFinished) {
etCPW.setText(String.valueOf(secsUntilFinished / 1000));
//etCPW.setText("seconds remaining: " + secsUntilFinished / 1000);
subViewGroup = findViewById(R.id.SB_NO_ACTION);
subViewGroup.setVisibility(View.VISIBLE);
}
#Override
public void onFinish() {
etCPW.setText("Counter Done");
subViewGroup.setVisibility(View.GONE);
if(cdt!=null){
cdt.cancel();
}
}
};
cdt.start();
}
I have a like button in my RecyclerView,what I want is when user hit the like button for the 1st time,the button background color will change to red color,and when the same user hit the like button,the button will change back to default color which is white.
I checked for few SO question,but still havent get what I want.So far my solution is like below,doesnt produce any error but when clicked the button,nothing happen.
likeButton =(Button) view.findViewById(R.id.likeButton);
//here for user like the post
holder.likeButton.setOnClickListener(new View.OnClickListener() {
boolean clicked = true;
#Override
public void onClick(View v) {
if(!clicked){
holder.likeButton.setBackgroundColor(Color.RED);
clicked = true;
//here i will update the database
}else{
holder.likeButton.setBackgroundColor(Color.WHITE);
clicked = false;
//here i will update the database
}
}
});
I checked this SO answer too,so I modified my code as below,but still nothing happens when the button is clicked.
holder.likeButton.setBackgroundColor(Color.WHITE);
holder.likeButton.setOnClickListener(new View.OnClickListener() {
ValueAnimator buttonColorAnim = null;
#Override
public void onClick(View v) {
if(buttonColorAnim != null){
buttonColorAnim.reverse();
buttonColorAnim = null;
//here i will update the database
}else{
final Button button = (Button) v;//here is the line I dont undestand
buttonColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), Color.RED, Color.WHITE);
buttonColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
// set the background color
button.setBackgroundColor((Integer) animator.getAnimatedValue());
}
//here i will update the database
});
buttonColorAnim.start();
}
}
});
Somebody please point out what I'm missing,what I want is change button color programmatically when being click for 1st time,and change back to default for next click(which avoid multiple like from a same user).
You should create a selector file. Create a file in drawable folder like color_change.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#color/button_pressed"/> <!-- pressed -->
<item android:state_focused="true"
android:drawable="#color/button_focused"/> <!-- focused -->
<item android:drawable="#color/button_default"/> <!-- default -->
</selector>
and declare it in the button like this
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/color_change"
android:text="Click Me" />
Hi try to this hope this can help you...
In XML
<Button
android:id="#+id/btnClick"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:text="click"/>
In Adapter Class
boolean click = true;
holder.btnClick.setTag(position);
holder.btnClick.setId(position);
holder.btnClick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (click) {
holder.btnClick.setBackgroundColor(Color.RED);
click = false;
} else {
holder.btnClick.setBackgroundColor(Color.WHITE);
click = true;
}
notifyDataSetChanged();
}
});
Instead of clicked or not condition, make and use condition from you update database for like and dislike operation. So, In click-listener get data previously user like or not then change background and update database as per new click.
Try adding this line to your row.xml file in the main layout :
android:descendantFocusability="blocksDescendants"
Have a look at this. Here, I changed the button text color on click. First time, all buttons appear white and after click it toggles between red and white as you expected. --
//LikeAdapter.java
public class LikeAdapter extends RecyclerView.Adapter<LikeAdapter.LikeHolder> {
public LikeAdapter() {
}
#Override
public LikeAdapter.LikeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.like_item,parent,false);
return new LikeHolder(view);
}
#Override
public void onBindViewHolder(final LikeAdapter.LikeHolder holder, int position) {
holder.red_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.red_btn.getVisibility() == View.VISIBLE) {
holder.red_btn.setVisibility(View.GONE);
holder.white_btn.setVisibility(View.VISIBLE);
} else {
holder.red_btn.setVisibility(View.VISIBLE);
holder.white_btn.setVisibility(View.GONE);
}
}
});
holder.white_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.white_btn.getVisibility() == View.VISIBLE) {
holder.red_btn.setVisibility(View.VISIBLE);
holder.white_btn.setVisibility(View.GONE);
} else {
holder.red_btn.setVisibility(View.GONE);
holder.white_btn.setVisibility(View.VISIBLE);
}
}
});
}
#Override
public int getItemCount() {
return 5;
}
public class LikeHolder extends RecyclerView.ViewHolder {
private Button red_btn, white_btn;
public LikeHolder(View itemView) {
super(itemView);
red_btn = (Button) itemView.findViewById(R.id.red_btn);
white_btn = (Button) itemView.findViewById(R.id.white_btn);
red_btn.setBackgroundColor(Color.RED);
white_btn.setBackgroundColor(Color.WHITE);
}
}
}
//like_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp">
<Button
android:id="#+id/red_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Red"/>
<Button
android:id="#+id/white_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="White"/>
</RelativeLayout>
I have a quiz app, and every question has 4 answers, 2 of them are the correct ones. I use CheckBox for the answers. What I want is when the user clicks on 2 of the answers, then the remaining 2 to get unchecked. With other words, only 2 checked CheckBox at the time, and if the user has 2 checked and checks third one, then one of the two checked to get unchecked. I write a code that it is "half-working". When I check CheckBox starting from the first to the last is working, but clicking from the last to the first, nothing happens...
public void checkBoxClicked(View view) {
switch (view.getId()) {
case R.id.checkBoxOne:
case R.id.checkBoxTwo:
case R.id.checkBoxThree:
case R.id.checkBoxFour:
if (checkBoxOne.isChecked() && checkBoxTwo.isChecked()) {
checkBoxThree.setEnabled(false);
checkBoxFour.setEnabled(false);
}else {
checkBoxThree.setEnabled(true);
checkBoxFour.setEnabled(true);
}
if (checkBoxOne.isChecked() && checkBoxThree.isChecked()) {
checkBoxTwo.setEnabled(false);
checkBoxFour.setEnabled(false);
}else {
checkBoxTwo.setEnabled(true);
checkBoxFour.setEnabled(true);
}
if (checkBoxOne.isChecked() && checkBoxFour.isChecked()) {
checkBoxTwo.setEnabled(false);
checkBoxThree.setEnabled(false);
}else {
checkBoxTwo.setEnabled(true);
checkBoxThree.setEnabled(true);
}
if (checkBoxTwo.isChecked() && checkBoxThree.isChecked()) {
checkBoxOne.setEnabled(false);
checkBoxFour.setEnabled(false);
}else {
checkBoxOne.setEnabled(true);
checkBoxFour.setEnabled(true);
}
if (checkBoxTwo.isChecked() && checkBoxFour.isChecked()) {
checkBoxOne.setEnabled(false);
checkBoxThree.setEnabled(false);
}else {
checkBoxOne.setEnabled(true);
checkBoxThree.setEnabled(true);
}
if (checkBoxThree.isChecked() && checkBoxFour.isChecked()) {
checkBoxOne.setEnabled(false);
checkBoxTwo.setEnabled(false);
}else {
checkBoxOne.setEnabled(true);
checkBoxTwo.setEnabled(true);
}
break;
I would try tracking the boxes that are checked using an array, (a queue would work perfect for this). When the user clicks on a checkbox, check if your array has two entries. If it has less than 2 entries, add the new checkbox to the list. If it has two entries, remove the first checkbox from the list, and add the new checkbox.
After your tracking code, you can simply uncheck ALL of the check boxes and only check those that you want.
Here I use an ArrayList for simplicity, but even a simple array would work. You could also use the id's instead of the actual views.
***Update Very Simple Working example.
Activity
public class TestActivity extends AppCompatActivity implements View.OnClickListener{
private ArrayList<CheckBox> mChecks;
private ArrayList<CheckBox> mSelectedChecks;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
mChecks = new ArrayList<CheckBox>();
mSelectedChecks = new ArrayList<CheckBox>();
//Load All checkboxes
CheckBox check1 = (CheckBox)findViewById(R.id.check1);
CheckBox check2 = (CheckBox)findViewById(R.id.check2);
CheckBox check3 = (CheckBox)findViewById(R.id.check3);
CheckBox check4 = (CheckBox)findViewById(R.id.check4);
//Add to tracking list
mChecks.add(check1);
mChecks.add(check2);
mChecks.add(check3);
mChecks.add(check4);
//Add Click listener
for(CheckBox c : mChecks) {
c.setOnClickListener(this);
}
}
#Override
public void onClick(View view) {
CheckBox c = (CheckBox)view;
if(mSelectedChecks.contains(c)) {
mSelectedChecks.remove(c);
} else {
if(mSelectedChecks.size() < 2) {
mSelectedChecks.add(c);
} else {
mSelectedChecks.remove(0);
mSelectedChecks.add(c);
}
}
drawResults();
}
public void drawResults() {
for(CheckBox c : mChecks) {
c.setChecked(mSelectedChecks.contains(c));
}
}
}
Layout file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:text="Check 1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/check1"/>
<CheckBox
android:text="Check 2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/check2"/>
<CheckBox
android:text="Check 3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/check3"/>
<CheckBox
android:text="Check 4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/check4"/>
</LinearLayout>
I have a text view in which the user can enter data at run time using the custom buttons that I have created.
My delete button is able to delete one character at a time but if i hold the button then it stops.
I want the text field to get cleared when i hold the button.
Is there any solution to this....??
Please help me out.
This is my xml,
<RelativeLayout
android:id="#+id/btnClear"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
>
<ImageView
android:id="#+id/imgClear"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/img_clear" />
</RelativeLayout>
This is my code,
imgClear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String getNumber;
if(isFirstNum){
getNumber = txtFirstNumber.getText().toString();
if(getNumber.length() > 0)
txtFirstNumber.setText(getNumber.substring(0, getNumber.length()-1));
} else if(!isFirstNum){
getNumber = txtSecondNumber.getText().toString();
if(getNumber.length() > 0)
txtSecondNumber.setText(getNumber.substring(0, getNumber.length()-1));
}
}
});
You can use the onLongClickListener to check if the delete button is pressed for a long time
imgClear.setOnLongClickListener(new OnLongClickListener()
{
#Override
public boolean onLongClick(View v)
{
txtFirstNumber.setText("");
return true;
}
});
This will set your txtFirstNumber to blank but the onClickListener will not be called.
Your question is not clear. But as per my understanding you want to clear the text of the text view then in your button click listener just set the text for textview to empty.
eg:
public void onClick(View v){
textview.setText("");
}
In the app I've been working on, I would like to have a multiple-state (in my case, three) toggle button, instead of the two that ToggleButton provides. I've tried to start my own that extends Button, following the CompoundButton source, but quite honestly reading over its source got a bit overwhelming.
Is there a way to do a three-state toggle button using just a selector xml or something, or perhaps another method I haven't thought of? I'm rather at a loss of how to do this.
I implemented a multi-state toggle button, the source code is here
This is how it looks:
And it's quite easy to use it:
<org.honorato.multistatetogglebutton.MultiStateToggleButton
android:id="#+id/mstb_multi_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
mstb:values="#array/planets_array" />
In your activity:
MultiStateToggleButton button2 = (MultiStateToggleButton) this.findViewById(R.id.mstb_multi_id);
button2.setOnValueChangedListener(new ToggleButton.OnValueChangedListener() {
#Override
public void onValueChanged(int value) {
Log.d(TAG, "Value: " + value);
}
});
You can create a custom ImageButton to achieve this, you need 3 different images in this case.
You can also add more states if you want.
public class FlashButton extends ImageButton {
public enum FlashEnum {
AUTOMATIC, ON, OFF
}
public interface FlashListener {
void onAutomatic();
void onOn();
void onOff();
}
private FlashEnum mState;
private FlashListener mFlashListener;
public FlashButton(Context context, AttributeSet attrs) {
super(context, attrs);
//Sets initial state
setState(FlashEnum.AUTOMATIC);
}
#Override
public boolean performClick() {
super.performClick();
int next = ((mState.ordinal() + 1) % FlashEnum.values().length);
setState(FlashEnum.values()[next]);
performFlashClick();
return true;
}
private void performFlashClick() {
if(mFlashListener == null)return;
switch (mState) {
case AUTOMATIC:
mFlashListener.onAutomatic();
break;
case ON:
mFlashListener.onOn();
break;
case OFF:
mFlashListener.onOff();
break;
}
}
private void createDrawableState() {
switch (mState) {
case AUTOMATIC:
setImageResource(R.drawable.ic_flash_auto);
break;
case ON:
setImageResource(R.drawable.ic_flash_on);
break;
case OFF:
setImageResource(R.drawable.ic_flash_off);
break;
}
}
public FlashEnum getState() {
return mState;
}
public void setState(FlashEnum state) {
if(state == null)return;
this.mState = state;
createDrawableState();
}
public FlashListener getFlashListener() {
return mFlashListener;
}
public void setFlashListener(FlashListener flashListener) {
this.mFlashListener = flashListener;
}
}
You can certainly define a selector to use as a background that has three entries. The question is what button attributes you can use for the selector. You can have two boolean attributes, say A and B, and define the selector in terms of A, B, and default. (A && B will satisfy A, so more properly they could be thought of as A, !A && B, and !A && !B.) You can overload existing attributes (selected, focused, etc.) or, more elegantly, define your own custom attributes using the recipe described in this thread.
Why not use RadioGroup and style radios inside?
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:background="#drawable/your_drawable_selector"
android:button="#android:color/transparent"
android:gravity="center_horizontal" //center text
android:text="text"
/>
...
Chip is a very good native option.
<com.google.android.material.chip.ChipGroup
android:id="#+id/chip_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:singleSelection="true">
<com.google.android.material.chip.Chip
android:id="#+id/first_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Todo"
android:textAppearance="?android:attr/textAppearance"
android:textColor="#color/black"
android:checkable="true"
style="#style/Widget.MaterialComponents.Chip.Choice"
app:chipBackgroundColor="#color/colorAccent"/>
<!-- Second Chip -->
<!-- Third Chip -->
</com.google.android.material.chip.ChipGroup>
binding.chipGroup.setOnCheckedChangeListener { chipGroup, i ->
when (i) {
binding.firstChip -> {
binding.firstChip.setChipBackgroundColorResource(R.color.colorAccent)
}
else -> {}
}
}
binding.firstChip.isChecked = true //default
GL
Source