I have a little problem. I have button with textview beside it. I want to touch the button when the textview is touched (effect: button is highlighted when I touch the button). Is there some easy way to do this? I cannot find any appriopriate function.
Edit: Okay, I've fixed my problem. It is:
hilfeText.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent me) {
int action = me.getAction();
if(action == MotionEvent.ACTION_DOWN) {
hilfe.setPressed(true);
return true;
} else if (action == MotionEvent.ACTION_UP) {
hilfe.setPressed(false);
return true;
}
return false;
}
});
You can define the click and focus mode of a button in xml file
like
`
<item android:drawable="#drawable/recordings_icon" android:state_enabled="false"></item>
<item android:drawable="#drawable/recordings_glow" android:state_enabled="true" android:state_pressed="true"/>
<item android:drawable="#drawable/recordings_shadow" android:state_enabled="true" android:state_focused="true"/>
<item android:drawable="#drawable/recordings_icon" android:state_enabled="true"/>
you can put this file in a directory name drawables
#drawable/recordings_icon is an image file
you just declare this filename as background for button layout xml file
<Button
android:id="#+id/buttonActivate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/xmlfilename" />
You can call performClick() method using Button reference inside onClick of TextView.
example-
myTextView.setOnClickListner(){
public void onClick(){
myButton.performClick();
--------------code
}
}
Setup an onClickListener for your Button and TextView and in the onClick(), let them both call the same function. Simple.
This might do the trick
TextView v = ...;
final Button b = ...;
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
b.setFocusableInTouchMode(true);
b.requestFocus();
b.performClick();
}
});
Related
I'm having a problem with my Button staying in a highlighted state, after doing the following:
public class MainActivity extends AppCompatActivity {
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
}
}
Concerning the code above, when using it, I'm expecting the button click to be handled by the touch, and by returning "true" the handling should stop at the touchListener.
But this is not the case. The button stays in a highlighted state, even though the click is being called.
What I get is:
Test - calling onClick
Test - Performing click
on the other hand, if I'm using the following code, the button is clicked, same prints, but the button doesn't end up stuck in a highlighted state:
public class MainActivity extends AppCompatActivity {
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
// v.performClick();
Log.d("Test", "Performing click");
return false;
}
}
return false;
}
});
}
}
I'm a bit confused as to what's the responder chain to the touch event. My guess is that it's:
1) TouchListener
2) ClickListener
3) ParentViews
Can someone confirm this as well?
Such customizations need no programmatically modifications. You can do it simply in xml files. First of all, delete the setOnTouchListener method that you provide in the onCreate entirely. Next, define a selector color in the res/color directory like the following. (if the directory doesn't exist, create it)
res/color/button_tint_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#e0f47521" android:state_pressed="true" />
<item android:color="?attr/colorButtonNormal" android:state_pressed="false" />
</selector>
Now, set it to the button's app:backgroundTint attribute:
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:backgroundTint="#color/button_tint_color" />
Visual Result:
EDITED: (to address touch event issue)
From an overall point of view, the flow of the touch event starts from the Activity, then flows down to the layout (from the parent to the child layouts), and then to the views. (LTR flow in the following picture)
When the touch event reaches the target view, the view can handle the event then decide to pass it to the prior layouts/activity or not (returning false of true in onTouch method). (RTL flow in the above picture)
Now let's take a look at the View's source code to gain a deeper insight into the touch event flows. By taking a look at the implementation of the dispatchTouchEvent, we'd see that if you set an OnTouchListener to the view and then return true in its onTouch method, the onTouchEvent of the view won't be called.
public boolean dispatchTouchEvent(MotionEvent event) {
// removed lines for conciseness...
boolean result = false;
// removed lines for conciseness...
if (onFilterTouchEventForSecurity(event)) {
// removed lines for conciseness...
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) { // <== right here!
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
// removed lines for conciseness...
return result;
}
Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.
There is another issue with not calling the onTouchEvent, which is related to the pressed-state and you mentioned in the question. As we can see in the below code block, there is an instance of UnsetPressedState that calls setPressed(false) when it runs. The result of not calling setPressed(false) is that the view gets stuck in the pressed state and its drawable state doesn't change.
public boolean onTouchEvent(MotionEvent event) {
// removed lines for conciseness...
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
// removed lines for conciseness...
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
// removed lines for conciseness...
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
// removed lines for conciseness...
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClickInternal();
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
// removed lines for conciseness...
}
// removed lines for conciseness...
break;
// removed lines for conciseness...
}
return true;
}
return false;
}
UnsetPressedState:
private final class UnsetPressedState implements Runnable {
#Override
public void run() {
setPressed(false);
}
}
Regarding the above descriptions, you can change the code by calling setPressed(false) yourself to change the drawable state where the event action is MotionEvent.ACTION_UP:
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
// v.invalidate();
v.setPressed(false);
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
You are messing around touch and focus events. Let start with understanding behavior with same color. By default, there is Selector assigned as background to the Button in Android. So simply changing background color, make is static (color will not change). But it's not a native behavior.
Selector might look like this one.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="#drawable/bgalt" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="#drawable/bgalt" />
<item android:drawable="#drawable/bgnorm" />
</selector>
As you can see above, there is state focused and state pressed. By setting onTouchListener you will handle touch events, which have nothing to do with focus.
Selector of the Button should replace focus event with touch during click event on the button. But in first part of your code you intercepted events for the touch (returning true from callback). Color change cannot proceed further and is freezing with same color . And that is why second variant (without interception) are working fine and that is your confusion.
UPDATE
All you need to do it's to change behavior and color for the Selector. For ex. by using next background for the Button. AND remove onTouchListener from your implementation at all.
<?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/color_pressed" />
<item android:drawable="#color/color_normal" />
</selector>
if you assign a background to the button, it wont change the color on click.
<color name="myColor">#000000</color>
and set it as backgrount to your button
android:background="#color/myColor"
you can just use material Chips for instead of Button view.
refer : https://material.io/develop/android/components/chip
there they handle those hililghted events and you can customize with applying the themes.
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 would change imageView picture when it's pressed, and change it again when pressure is released. That ImageView contains picture of a button, and when is pressed i would give to user a feedback (like when he press a normal button) by change image. This is my code:
final ImageView imageView = (ImageView) findViewById(R.id.imageView1);
imageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("IMAGE", "motion event: " + event.toString());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
imageView.setImageResource(R.drawable.button_hover);
}
case MotionEvent.ACTION_UP: {
imageView.setImageResource(R.drawable.button);
}
}
return false;
}
});
and this is xml
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="std_button"
android:src="#drawable/button" />
but it doesn't work. If i use only ACTION_DOWN event, image change as i want,
What's wrong?
Make selector xml in drawable folder with content like this :
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_green" android:state_pressed="true"/>
<item android:drawable="#drawable/ic_red"/>
</selector>
Try add break; after each case,
And as giozh said inside onTouch i return always false, so touch event result always not consumed. Just put return true after each case statement.
for change on event press you can try this.....
final ImageView imagen = (Imagen) findViewById(R.id.imageViewX);
ImageView imagen = (ImageView)findViewById(R.id.imageViewX);
imagen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ImageView perse = (ImageView) findViewById(R.id.imageViewX);
perse.setImageResource(R.drawable.backgroundtwo);
}
});
i am working on android.
i am creating a login button. i want that whenever i press login button then text color of that button should be changed.
and when this button pressed then login functionality should be performed.
for this i am coding like this:-
button_login.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
int action = arg1.getAction();
if(action == MotionEvent.ACTION_DOWN) {
button_login.setTextColor(Color.parseColor("#163D74"));
return true;
} else if (action == MotionEvent.ACTION_UP) {
button_login.setTextColor(Color.parseColor("#FFFFFF"));
return true;
}
return false;
}
});
button_login.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v)
{
// checking the functionality of login
}
});
but only onTouchListener is working. login functionality is not working.
please suggest me what mistake i have done. and how can i implement these both functionalities. means how can i change the color of text of button and how can i perform login functionality.
Thank you in advance.
You should just declare your login functionality when action is UP.
button_login.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
int action = arg1.getAction();
if(action == MotionEvent.ACTION_DOWN) {
button_login.setTextColor(Color.parseColor("#163D74"));
return true;
} else if (action == MotionEvent.ACTION_UP) {
// check logine functionality.
button_login.setTextColor(Color.parseColor("#FFFFFF"));
return true;
}
return false;
}
});
Its does the same thing with the same logic.
In onTouch method, you used return true; that means
True if the listener has consumed the event, false otherwise.
So you need to return false if you need it to consumed by other listeners
I think what you want to do is to change the UI state of button while pressing. For that you don't have to implement on touch... Just write an xml and put it on the src tag of button.
A. Create a new tag on colors.xml.. You can add colors as drawables.... which you will need on step two.
Write something like this in colors.xml
<drawable name="red">#0000ff</drawable>
B. Create a new xml in drawables folder, Name it what you like
write this in the xml, Here you can replace drawables here with drawable you can create with help of step A.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/android_pressed"
android:state_pressed="true" />
<item android:drawable="#drawable/android_focused"
android:state_focused="true" />
<item android:drawable="#drawable/android_normal" />
</selector>
This code is copied from here.. See Custom Button section.
C. Add this XML you created in step B as value of src attribute of your button, you have replaced of what I understood your onTouch is doing...