In an android application I am implementing an Animation on an ImageButton. After the animation the button remains at it's last frame but it is only clickable at it's initial position, I have Implemented an BounceInterpolation animation by these line of code in my main .java Activity
TranslateAnimation translation;
translation = new TranslateAnimation(0f, 0F, 0f, 200);
translation.setStartOffset(150);
translation.setDuration(100);
translation.setFillAfter(true);
translation.setInterpolator(new BounceInterpolator());
mTourButton.startAnimation(translation);
I don't know how to update the the ImageButton parameters. Most of the solutions are for the xml implemented animations. I didn't find any solution. I am tired now please help.
Try to use onTouch() to handle your clicks.
imageButton.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction())
{
case MotionEvent.ACTION_UP :
{
// Do whatever you want here.
}
return true;
}
});
That should do it.
Better add onClick in XML:
<ImageButton
android:onClick="doSomethingMethod"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageButton"
android:layout_above="#+id/imageView"
android:layout_centerHorizontal="true" />
Press ALT+ENTER on doSomethingMethod and Create 'doSomethingMethod(View)' in 'Activity'
This will create a method like onClickListener in your Activity.
Hope it helps!
Related
I have a custom floorplanView class within my main Activity. This custom view uses up roughly half the screen space. I am trying to simply create a star image and place it on the floor plan onTouch. However, for some reason this appears to place the image below where I am touching (I have tried a few variations and cannot work it out).
public class FloorplanView extends RelativeLayout {
public FloorplanView(Context context, AttributeSet attrs) {
super(context, attrs);
SCROLL_THRESHOLD = getResources().getDimensionPixelSize(R.dimen.margin5);
setClipChildren(false);
setOnTouchListener(new FloorplanTouchListener());
}
public class FloorplanTouchListener implements View.OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
posX = event.getRawX() - v.getX();
posY = event.getRawY() - v.getY();
break;
case MotionEvent.ACTION_UP:
ImageView img = new ImageView(getContext());
img.setOnTouchListener(new FlagTouchListener());
img.setBackground(getResources().getDrawable(android.R.drawable.btn_star));
img.setX(event.getRawX()); //Used posX/Y without success
img.setY(event.getRawY());
addView(img);
break;
}
return true;
}
}
}
Further to this, is there a way to set bounds to my custom class with extends a relativeLayout so that when I drag and move my image (which is setup and working) it does not go outside of the Floorplanview custom class.
EDIT:
The parent Activity class XML
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.fcs_systems.inspector.FloorplanActivity">
<TextView
android:id="#+id/txtFloorplanName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Floorplan Name"
android:visibility="gone"/>
<com.fcs_systems.inspector.FloorplanView
android:id="#+id/floorplanView"
android:background="#color/fcs_red"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</RelativeLayout>
According to the documentation,
float getRawX () : Returns the original raw X coordinate of this event. For touch events on the screen, this is the original location of the event on the screen, before it had been adjusted for the containing window and views.
(Source : https://developer.android.com/reference/android/view/MotionEvent.html#getRawX() )
This is why getRawX() and getRawY() seem to place the image lower than where you tapped.
You should simply use the getX() and getY() methods on the MotionEvent instead.
As for your images going out of the RelativeLayout, this will depends on two things :
Add your images to your RelativeLayout (not sure what your actual addView(img); does)
Make sure your RelativeLayout doesn't have https://developer.android.com/reference/android/view/ViewGroup.html#setClipChildren(boolean) enabled
This will make sure that your images belong to your RelativeLayout container, and will not be drawn when moved outside of it.
There is a program generated scroll view like this:
The scroll view XML is just simple empty LinearLayout
<ScrollView>
<LinearLayout>
</LinearLayout>
</ScrollView>
Then , in the run time , I have an ArrayList<TextView>, and add the items to the ScrollView like this
for (TextView t : test_views) {
scroll_view.addView(t);
}
And now , I have one of the listView and I would like to scroll to that TextView programmatic , the case is quite special so that can not change the scrollview to listview, how to achieve that?
Thanks a lot for helping.
Try using scrollTo() function. More details available in this link http://developer.android.com/reference/android/widget/ScrollView.html#scrollTo(int, int)
Please check the below code.
sv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
tv.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
tv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
tv.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
Hope it will help you.
Let me know if you need any further help.
My Linear Layout: main_linear_layout contains four Linear Layouts: ll1 ll2 ll3 ll4. Each LinearLayout contains Buttons. I am trying to implement the onFling method on main_linear_layout. I want to be able to swipe anywhere on the Layout of Buttons and call an action.
Currently I am able to swipe anywhere on the screen except for the Layout of Buttons. I tried using the following code to fix the problem:
swipeLayout = (LinearLayout) findViewById(R.id.main_linear_layout);
//swipeLayout is the main Layout that contains 4 other linear layouts
swipeLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
gestureScanner.onTouchEvent(event);
return true;
}
});
But I am still not able to swipe on the Layout of Buttons. Does anybody know why this is? Is there something else I need to implement? Am I supposed to implement an OnTouchListener to every Linear Layout inside the main Linear Layout? Or to every Button in each Layout?
And in the xml I added a bunch of code to the main Linear Layout:
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:longClickable="true"
But this did not work either. Can someone please help?
If you have a LinearLayout, and then more layouts inside of that, and then buttons on those as you say you do, then this is functioning as intended.
You're only adding the listener to the outside layout...so of course, it'll only trigger when you slide on it. By sliding on the other layouts, or even the buttons, the slide event doesn't even get to that listener, because it is consumed.
You'd need to add the listener to each element that you want to be checking for.
One way to do this is to create an array of your buttons and do it all at once:
private Button button1;
private Button button2;
....
private Button button10;
...
protected void onCreate(Bundle b) {
super.onCreate(b);
button1 = findViewById(R.id.button1);
...
button10 = findViewById(R.id.button10);
OnClickListener onCL = new OnClickListener . . . //do all of your creation here
Button[] buttons = {button1, button2, . . . , button10};
for(Button b : buttons) {
b.setOnClickListener(onCL);
}
}
Well the reason the ll1,ll2,ll3,ll4 don't pick up on touch events is because the parent linear layout receives the motion event and it doesn't propagate further.
Why do you need a touch event listener on the main linear layout? Do you want the sub layouts to all fling together?
If you want the other layouts to pick up on the touch event return false on the touch listener
swipeLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
gestureScanner.onTouchEvent(event);
return false;
}
});
Or you could create 4 GestureDetectors and pass the event to the right one depending on which view was pressed
swipeLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(v.getId()){
case R.id.ll1:
gesture1.ontouchEvent(e);
break;
case R.id.ll2:
gesture1.ontouchEvent(e);
break;
}
//etc
return false;
}
});
I have an ImageView overlay inside of a RelativeLayout and want to prevent any clicks from going through the ImageView to the Buttons etc that are behind it (thus in effect disabling the entire RelativeLayout).
Is the a simpler way of doing this then iterating the RelativeLayout views and setting them to disabled as I currently am doing using this code:
RelativeLayout rlTest = (RelativeLayout ) findViewById(R.id.rlTest);
for (int i = 0; i < rlTest.getChildCount(); i++) {
View view = rlTest.getChildAt(i);
view.setEnabled(true);
}
you can set the image to be
android:clickable="true"
Simply call rlTest.setClickable(false). This will prevent the click to be propagate to the children
There is a much cleaner way
You can use:
android:onClick="preventClicks"
in XML and in your Activity
public void preventClicks(View view) {}
This works with fragments.
Example inside this Activity has multiple fragments overlapping one another, just by adding the XML attribute in the background of your fragment it will still call the Activity.preventClicks and will prevent touches on fragments behind it
The following solution works in the general case:
_container.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// NOTE: This prevents the touches from propagating through the view and incorrectly invoking the button behind it
return true;
}
});
It basically blocks any touches from propagating through the view by marking the touch event as handled.
This works on both UI controls and layout containers (ie: LinearLayout, FrameLayout etc.).
The solution to set "clickable" as false did not work for me for layout containers either in code or in the view XML.
I assume that you are using onClickListeners.
How about using onTouchListener instead of onClickListeners. By doing this you will have a control over how deep down in your hierarchy the touch even can be visible. For example, if you have toch listeners on a relative-layout(RL) and a image-view(IV)(contained in RL), and you assign touchListeners to both. Now if you return true from IV's touch event, the lower down member RL will not receive the touch event. However if you return false from from IV's touch event, the lower down member RL will receive the touch event.
Hope this helps!
Just add these two listeners:
// Set an OnTouchListener to always return true for onTouch events so that a touch
// sequence cannot pass through the item to the item below.
view.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.onTouchEvent(event);
return true;
}
});
// Set an OnHoverListener to always return true for onHover events so that focus cannot
// pass through the item to the item below.
view.setOnHoverListener(new OnHoverListener() {
#Override
public boolean onHover(View v, MotionEvent event) {
v.onHoverEvent(event);
return true;
}
});
You could use databindings and consume the clicks like this:
android:onClick="#{() -> true}"
In C#, I use an empty delegate:
objectName.Click += delegate {};
I haven't encountered any problems with it but it does prevent clicks from filtering through to underlying controls.
you can also se the root click listener to null:
// Do not process clicks on other areas of this fragment
binding.root.setOnClickListener(null)
This works 100%.
It doesnt affect other listeners that are already set on the fragment's views.
I made a very simple test application with one activity and one layout. The onClick doesn't trigger the first time it is pressed, as it should.
The activity:
package com.example.mytest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText ed1 = (EditText) findViewById(R.id.editText1);
ed1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG)
.show();
}
});
}
}
The layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/editText1"
android:ems="10" />
</RelativeLayout>
If you run this application, and click on the second editText and then back on the first one, it will not trigger the onClick. You can keep selecting back and forth and it will not trigger the onClick at all. I need this basic functionality, but haven't been able to think of a way to get it to work. Ideas?
Notice
I have tried all of the methods recommended on my API level 16 physical device and my API level 8 emulator, but I get the same problem.
Clarification
When editText1 is focused and is clicked on, then the onClick method fires. If editText2 is focussed, and then editText1 is clicked, it doesn't fire. Big problem.
Overview, when a user interacts with any UI component the various listeners are called in a top-down order. If one of the higher priority listeners "consumes the event" then the lower listeners will not be called.
In your case these three listeners are called in order:
OnTouchListener
OnFocusChangeListener
OnClickListener
The first time the user touches an EditText it receives focus so that the user can type. The action is consumed here. Therefor the lower priority OnClickListener is not called. Each successive touch doesn't change the focus so these events trickle down to the OnClickListener.
Buttons (and other such components) don't receive focus from a touch event, that's why the OnClickListener is called every time.
Basically, you have three choices:
Implement an OnTouchListener by itself:
ed1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(MotionEvent.ACTION_UP == event.getAction())
editTextClicked(); // Instead of your Toast
return false;
}
});
This will execute every time the EditText is touched. Notice that the listener returns false, this allows the event to trickle down to the built-in OnFocusChangeListener which changes the focus so the user can type in the EditText.
Implement an OnFocusChangeListener along with the OnClickListener:
ed1.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
editTextClicked(); // Instead of your Toast
}
});
This listener catches the first touch event when the focus is changed while your OnClickListener catches every other event.
(This isn't a valid answer here, but it is a good trick to know.) Set the focusable attribute to false in your XML:
android:focusable="false"
Now the OnClickListener will fire every time it is clicked. But this makes the EditText useless since the user can no longer enter any text...
Note:
getApplicationContext() can create memory leaks. A good habit is to avoid using it unless absolutely necessary. You can safely use v.getContext() instead.
I'm probably too late to the party, but here is a code snipped which fixes the issue with onClick() not being called:
ed1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !v.hasFocus()) {
// onClick() is not called when the EditText doesn't have focus,
// onFocusChange() is called instead, which might have a different
// meaning. This condition calls onClick() when click was performed
// but wasn't reported. Condition can be extended for v.isClickable()
// or v.isEnabled() if needed. Returning false means that everything
// else behaves as before.
v.performClick();
}
return false;
}
});
make edit text clickable..
In XML android:clickable="true"
or in code
ed1.setClickable(true);
then do
ed1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getBaseContext(), "1",Toast.LENGTH_SHORT).show();
}
});
This happens because the first tap gains the focus into the view. The next tap triggers the click.
If you are inflating the view dynamically, do this:
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
If this doesn't work, try applying it on the parent view as well.
Its the most simplest way to work with date picker.
private DatePickerDialog datePickerDialog;
EditText etJoiningDate;
etJoiningDate=(EditText)findViewById(R.id.etJoiningDate);
etJoiningDate.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
final Calendar cldr = Calendar.getInstance();
int day = cldr.get(Calendar.DAY_OF_MONTH);
int month = cldr.get(Calendar.MONTH);
int year = cldr.get(Calendar.YEAR);
// date picker dialog
datePickerDialog = new DatePickerDialog(TestActivity.this,
new DatePickerDialog.OnDateSetListener() {
#Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
etJoiningDate.setText(dayOfMonth + "/" + (monthOfYear + 1) + "/" + year);
}
}, year, month, day);
datePickerDialog.show();
break;
}
return false;
}
});
public class TestProject extends Activity implements OnClickListener {
TextView txtmsg;
EditText ed1, ed2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtmsg = (TextView) findViewById(R.id.txtmsg);
ed1 = (EditText) findViewById(R.id.edt1);
ed2 = (EditText) findViewById(R.id.edt2);
ed1.setOnClickListener(this);
ed2.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==ed1){
txtmsg.setText("1");
Toast.makeText(this, "first",Toast.LENGTH_SHORT).show();
}
if(v==ed2){
txtmsg.setText("2");
Toast.makeText(this, "second",Toast.LENGTH_SHORT).show();
}
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/edt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" />
<EditText
android:id="#+id/edt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/edt1"
android:layout_marginTop="14dp"
android:ems="10" />
<TextView
android:id="#+id/txtmsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/edt2"
android:layout_below="#+id/edt2"
android:layout_marginRight="22dp"
android:layout_marginTop="160dp"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
Took me a minute to figure this out one time when this happened to me. My ImageButton with a setOnClickListener and onClick didn't seem to fire and then I realized it was actually underneath another element in my xml layout, so I turned this:
<RelativeLayout>
<ImageButton>
<LinearLayout></LinearLayout>
</RelativeLayout>
into this:
<RelativeLayout>
<LinearLayout></LinearLayout>
<ImageButton>
</RelativeLayout>
and suddenly the ImageButton was not being overlapped by the other layout since it was now added later to the parent layout and was now on top and works every time. Good luck, always fun when basic stuff suddenly seems to stop working
Avoid using a FocusChangeListener since it will behave erratically when you don't really need it (eg. when you enter an activity). Just set an OnTouchListener along with your OnClickListener like this:
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view.requestFocus();
break;
}
return false;
}
This will cause your EditText to receive focus at first, and your onClick to function properly the first time.
Simple, Reuseable Kotlin Solution
I started with two custom extension functions:
val MotionEvent.up get() = action == MotionEvent.ACTION_UP
fun MotionEvent.isIn(view: View): Boolean {
val rect = Rect(view.left, view.top, view.right, view.bottom)
return rect.contains((view.left + x).toInt(), (view.top + y).toInt())
}
Then listen to touches on the Edittext. This will only fire if initial ACTION_DOWN event was originally on the Edittext, and still is.
myEdittext.setOnTouchListener { view, motionEvent ->
if (motionEvent.up && motionEvent.isIn(view)) {
// Talk your action here
}
false
}