I'm new in Android app developing and I realized that, at the end of the day, what truly matters to the end user is the App's UI.
I always try to do my best when it comes to UI's, but I always end up having some troubles.
In particular, one of the main problems I always have and I don't know how to fix, is that when I set a custom background color or image to some button, the click effect disappears. So you click the button and although it obviously works, it's pretty unpleasant to see how it does nothing graphically.
I'd like to know if there's some way to get the original effect back, or set some click effect myself programmatically.
Thanks in advance.
Save this as a drawable and set as the background:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#212121"/>
<corners android:radius="5dp"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#424242"/>
<corners android:radius="5dp"/>
</shape>
</item>
</selector>
This is just a simple example. You can create more complicated ones yourself.
Lets say you have a button or a TextView or any other view. and you want it to change its color during touch event and also to do something after the click:
button.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE)
{
v.setBackgroundColor(Color.parseColor("#000000"));
}
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)
{
v.setBackgroundColor(Color.parseColor("#ffffff"));
}
return false;
}
});
and then add click listener:
button .setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
do some stuff...
}
});
Thanks to Amir Horev's answer I could figure out what I really needed. I based my solution on his answer but instead of calling the setBackgroundColor() method, I used the setColorFilter() one instead from the background of the view, to trigger both the ACTION_DOWN and ACTION_UP events. So now I can basically set a color filter to any button. This is how the code finally looked like:
button.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
v.getBackground().setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0xFFAA0000));
}
if (event.getAction() == MotionEvent.ACTION_UP)
{
v.getBackground().setColorFilter(new LightingColorFilter(0xFFFFFFFF, 000000000));
}
return false;
}
});
I also wrote a function like public void triggerActionDownEvent(Button button); so I can call this funciton instead of writing all of the previous code for every button. Now I'll have to ensure that no more than one button is pressed at anytime.
I suggest you to set the color or the image programmatically. You can use:
Button button = (Button)findViewById(R.id.myButton);
button.setImageSource(R.drawable.image);
Related
In my application the background of buttons should change to another one when the user touch, and get back to the original one when the finger is off, my problem is that touching for a long period makes it change while touching for a short one, doesn't!! here's how I implemented that:
Button b = (Button) findViewById(R.id.b_bb_e_l);
b.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
b.setBackgroundResource(R.drawable.button_bb_e_l_selec);
break;}
case MotionEvent.ACTION_UP: {
b.setBackgroundResource(R.drawable.button_bb_e_l);
break;}
}
return false;
}
});
You can use drawable and shape to implement it.
Create a file such btn_bg.xml in res/drawable
btn_bg.xml's content:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/button_bb_e_l_selected"/>
<item android:drawable="#drawable/button_bb_e_l"/>
</selector>
Set background to your button:
<Button
android:background="#drawable/btn_bg"/>
If you are not required to use onTouch, you can create a style with background set to drawable. Create that drawable as xml that uses selectors and set the selectors' different states, state_pressed="true" and state_pressed="false" and apply the colors to those states. Then use that style on the buttons you want.
I have a custom view, when the user presses and holds on the view, I want to change its main display, then change it back when they let go. Androids listeners dont seem to have some sort of onRelease function.
myView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
//do something when pressed down
return true;
}
else if(event.getAction() == MotionEvent.ACTION_UP){
//do something when let go
return true;
}
return false;
}
});
Did you try this? I am using this now and it works fine :)
Create the following xml in drawable directory
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/button_bg_selected" android:state_selected="true"></item>
<item android:drawable="#drawable/button_bg_pressed" android:state_pressed="true"></item>
<item android:drawable="#drawable/button_bg_normal"></item>
</selector>
And set the view background to that drawable. Done :)
I'm rather new to android programming and I hit a bump. I want to make a button that changes it's state when pressed, so it will have to states pressed and not pressed. I managed to make the button change state to pressed and keep it like that but I don't know how to make it go back to the not pressed state when clicked again.
here is my code.
<Button
android:id="#+id/scaunstg"
android:layout_width="170dp"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="#drawable/scaunstg"
android:baselineAlignBottom="true"
android:clickable="true" />
the button has an xml file that controls the image displayed.
scaunstg.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// show interest in events resulting from ACTION_DOWN
if(event.getAction()==MotionEvent.ACTION_DOWN) return true;
// don't handle event unless its ACTION_UP so "doSomething()" only runs once.
if(event.getAction()!=MotionEvent.ACTION_UP) return false;
// doSomething();
scaunstg.setPressed(true);
return true;
}
});
Any ideas?
Thank you.
Instead of calling setPressed(true) ever time, we need to get the current state of the button and then call setPressed to the opposite. So if the button is pressed, we want to call setPressed(false), and if the button is unpressed then setPressed(true).
We can use the button's isPressed() method for this, and then use the not operator (!) to get the opposite.
scaunstg.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
// show interest in events resulting from ACTION_DOWN
if (event.getAction() == MotionEvent.ACTION_DOWN)
return true;
// don't handle event unless its ACTION_UP so "doSomething()" only runs once.
if (event.getAction() != MotionEvent.ACTION_UP)
return false;
// doSomething();
scaunstg.setPressed( !scaunstg.isPressed() );
return true;
}
});
So, you can do this via XML.To be more exact ,create a xml file in drawable folder (create the folder too, if you don't have it yet)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:drawable="#drawable/btn_sendemail_disable" />
<item
android:state_pressed="true"
android:state_enabled="true"
android:drawable="#drawable/btn_send_email_click" />
<item
android:state_focused="true"
android:state_enabled="true"
android:drawable="#drawable/btn_sendemail_roll" />
<item
android:state_enabled="true"
android:drawable="#drawable/btn_sendemail" />
</selector>
So, you just give your button a link to this xml file as resource.
I've been trying to look for a solution, but it seems like no one tried it, or maybe its too simple that I did not find it.
Anyways, I'm trying to achieve a button press with an ImageView. What I want is, ImageView to display a default image, and if pressed (OnTouch) [which has a MotionEvent.ACTION_DOWN block] to run a frame animation. When you release the touch [which has a MotionEvent.ACTION_UP block], it should stop the animation and return to the default image.
Note: Frame animation is continuous repeating, and should not include the default image as one of the looped through image. (Button up image should not be displayed when touching)
Now the problem is, I have the animation working, but as per the android documentation, the first item in the <animation-list> tag will be displayed by default. But if I add the default image (button un-touched state) as the first item, it will be displayed in the loop. Also, when I release the touch, I use stop() method of the AnimationDrawable, which stops the animation at the current frame (image) and I can't seem to find any way to stop and go to default image state.
Here is my code:
button_anim.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:drawable="#drawable/button1_press1" android:duration="200" />
<item android:drawable="#drawable/button1_press2" android:duration="200" />
<item android:drawable="#drawable/button1_press3" android:duration="200" />
</animation-list>
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
button = (ImageView)findViewById(R.id.imageView1);
button.setBackgroundResource(R.drawable.button_anim);
buttonAnim = (AnimationDrawable)button.getBackground();
button.setOnTouchListener(buttonTest);
}
private OnTouchListener buttonTest = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
buttonAnim.start();
// Log.d("Test", "Touch down");
} else if (action == MotionEvent.ACTION_UP) {
buttonAnim.stop();
// Log.d("Test", "Touch Stop");
}
return true;
}
};
Default image:- button1_inactive.png
buttonAnim.stop();
buttonAnim.reset();
// Log.d("Test", "Touch Stop");
AnimationDrawable mFrameAnimation = (AnimationDrawable)button.getBackground();
mFrameAnimation.stop();
mFrameAnimation.setVisible(true, true);
I create views dynamically, and I handle their click events normally, like this :
myView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
v.setBackgroundColor(0xaaffffff);
}
});
But this code does not handle the onRelease event, so the view remains with white background, after the click.
So how can I set the background to another value when the clicked state is over ?
Thanks in advance !
Edit:
OnTouchListener does the exact same thing. I guess I need something like onReleaseListener ?
For that you need to use an onTouchListener => documentation
Refer this tutorial on how to use this.
Example:
myView.setOnTouchListener(
new View.OnTouchListener() {
public boolean onTouch(View myView, MotionEvent event) {
int action = event.getAction();
if (action==MotionEvent.ACTION_MOVE)
{
myView.setBackgroundColor(Color.BLUE);
}
if (action==MotionEvent.ACTION_UP)
{
myView.setBackgroundColor(Color.RED);
}
if (action==MotionEvent.ACTION_DOWN)
{
myView.setBackgroundColor(Color.YELLOW);
}
// TODO Auto-generated method stub
return true;
}
}
Android has a selector for this. Define it in a xml file in your drawable folder and use it as background:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="#drawable/YOURDRAWABLE" />
<item android:state_pressed="true" android:drawable="#drawable/YOURDRAWABLE_WHEN_CLICKED" />
</selector>
Check the DOCUMENTATION
State lists are meant to be for style updates on state changes. Check this out.
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
You dont need to go for such cómplicated method for capturing a "click" event. Just for this method :-
//Inside on touch listener of course :-
KOTLIN :-
if(event.action == MotionEvent.ACTION_UP && event.action != MotionEvent.ACTION_MOVE) {
// Click has been made...
// Some code
}
JAVA :-
Just replace event.action with event.getAction()
This works for me 😉