I am making an alarm clock.
I want to make an activity which on the layout part is empty (exept a photo on the background)
I want to do, that if i touch anywhere on the screen, the music will stop.
I thought about making the img as a imageview...
but it dosent strach on the screen when I do it (even if the parameters are on the whole screen)
help?
in your layout verify that :
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
then try to use onTouchListener
then try :
yourActivityLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// action to do
return true;//always return true to consume event
}
});
Do this way to put touch event on Whole Activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
// do your work here
return true;
} else {
return false;
}
}
}
Have your Activity or Fragment implement OnClickListener, and then assign it as your click listener to every view and or layout.
in the first line of the function just run some logic,
#override
public void onClick(view v)
{
if(isMusicPlaying)
stopMusic();
// here run the rest of your logic
if (v == someButton){}
}
If you want if touch the layout , set click listener to the layout it self
You may play with WindowManager and overlaying your layout over everything else(may also overlay status bar and other system UI)
WindowManager instance has addVieW() method. With right layout params it produces described result
Try this, Pass your topmost parent as argument for this method
Eg: stopMusicOnTouch(yourParentView);
public void stopMusicOnTouch(View view) {
//Set up touch listener for non-text box views to hide keyboard.
if(!(view instanceof ImageView)) {
view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// Stop music here
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
stopMusicOnTouch(innerView);
}
}
}
At the end,I made a button for the whole screen and did it transperent (but visible)
it worked perefectly, and I suggest it to others!
Related
I want to remove a gridView item's shadow when the user presses it, and then restore it once the user releases. (cant use selector.xml because items have a user chosen color)
this code removes shadow when first pressed but upon release it stays stuck down with no shadow.
gridItemView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
image.removeShadow();
image.invalidate();
}
else if(event.getAction()==MotionEvent.ACTION_UP){
image.setShadow();
image.invalidate();
}
return false;
}
});
I cant set it to true, because then .OnItemClickListener in the fragment dosent work. Also I kinda fixed it by setting the shadow to turn on in onItemClickListener, but if the user slides their thumb off the item instead of just clicking it will stay pressed
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MainActivity.selectedItem = position;
if (lastView[0] != null) {
lastView[0].setBackgroundResource(R.drawable.nullr);
}
picker.setOldCenterColor(MainActivity.items.get(MainActivity.selectedItem).getColor());
picker.setColor(MainActivity.items.get(MainActivity.selectedItem).getColor());
View imageContainer = view.findViewById(R.id.imageContainer);
CircularImageView circleImage = (CircularImageView) view.findViewById(R.id.circleView);
artistText.setText(MainActivity.items.get(position).getArtist());
songText.setText(MainActivity.items.get(position).getSong());
int backgroundColor = Color.parseColor("#FFEECC");
GradientDrawable drawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{backgroundColor, backgroundColor});
drawable.setShape(GradientDrawable.OVAL);
drawable.setStroke(25, MainActivity.items.get(MainActivity.selectedItem).getColor());
imageContainer.setBackgroundDrawable(drawable);
circleImage.setShadow();
circleImage.invalidate();
lastView[0] = imageContainer;
MainActivity.anItemIsSelected = true;
}
});
you forgot
else if(event.getAction()==MotionEvent.ACTION_UP){
image.setShadow();
image.invalidate();
}
what you can do here is try to create a custom Gridview and override onTouchEvent, something like this, (it is not precisely accurate though)
public class MyGridv extends GridView{
//implement all constructors;
//the override onTouchEvent(MotionEvent event);
#override
protected boolean onTouchEvent(MotionEvent event){
// put your ontouch code here and return true, you might need to do
//some changes because you can not get access to your methods or
//you can make this class a private class to your mainActivity
// now delete your ontouch for your gridview
}
}
the logic here is onTouchEvent() is initially called before your onTouchListenerand its the first to be called, returning true there will then pass the event to onTouch() and on onClick, there everything will work fine
hope its helpful
Try to add below on your View.
android:clickable="true"
I am working on an android app and I want to appear a textview as winker. Simplest way may be that visible and invisible permanently textView.I unfortunately am weak at most of technique.
What should I do for having such graphics working.
yourtextview.setVisibility(View.VISIBLE); //for visible
yourtextview.setVisibility(View.INVISIBLE); //for invisible
yourtextview.setVisibility(View.GONE); //for remove textview from Layout Spaces
If you want to Hide/Show your TextView then refer below part of code.
There are 3 methods to Hide/Show as below:
View.VISIBLE : This method will make your View Visible.
View.INVISIBLE : This method will make your view Invisible, but space will be occupied of that view, space will not be gone.
View.GONE : This method also make your View Invisible but space of that View will also be Invisible.
You can use that 3 methods like below:
//Instead of textView you can use any view like ListView, GridView, ImageView etc.
textview.setVisibility(View.VISIBLE);
textview.setVisibility(View.INVISIBLE);
textview.setVisibility(View.GONE);
If you want to dynamically do the following
pass the visibility flag to isTextVisble(flag) method //you need to pass the flag
private void isTextVisble(boolean isVisible) {
if(isVisible)
txtView.setVisibility(View.VISIBLE);
else
txtView.setVisibility(View.GONE);
}
here you can use one button link on touch it will disapper like that you can create how manny buttons you want extra
/handle write click/
Button.setOnClickListener(new View.OnClickListener() {
//#Override
public void onClick(View v) {
Text1.setVisibility(View.INVISIBLE);
Text2.setVisibility(View.INVISIBLE);
Text3.setVisibility(View.INVISIBLE);
Text4.setVisibility(View.INVISIBLE);
if(Text.length() != 0)
deviceAddress = (byte) Integer.parseInt(Text.getText().toString());
else
deviceAddress = 00; /*default*/
Text.setText(Integer.toString(deviceAddress));
}
});
/*select the frequency*/
freqText.setOnTouchListener(new View.OnTouchListener() {
//#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Text1.setVisibility(View.VISIBLE);
Text2.setVisibility(View.VISIBLE);
Text3.setVisibility(View.VISIBLE);
Text4.setVisibility(View.VISIBLE);
return false;
}
});
/*set the selected value*/
Text1.setOnTouchListener(new View.OnTouchListener() {
//#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Text.setText(freqText1.getText().toString());
Text1.setVisibility(View.INVISIBLE);
Text2.setVisibility(View.INVISIBLE);
Text3.setVisibility(View.INVISIBLE);
Text4.setVisibility(View.INVISIBLE);
return false;
}
});
I have a relativelayout and have coded the onTouchListener to highlight background as follows:
relative3.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View arg0, MotionEvent event)
{
if(event.getAction()==MotionEvent.ACTION_DOWN )
{
relative3.setBackgroundColor(getResources().getColor(R.color.tran_grey));
}
if((event.getAction()==MotionEvent.ACTION_UP || event.getAction()==MotionEvent.ACTION_CANCEL))
{
relative3.setBackgroundColor(getResources().getColor(android.R.color.transparent));
}
return true;
}
});
and to perform an action upon onClick
relative3.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
custom_toast("Redirecting...");
}
});
Question:
The relativelayout could show highlight upon ACTION_DOWN and turn back to transparent upon ACTION_UP. Yet it is clicked, the toast simply does not appear as coded.
How could that be modified? Thanks!
Make sure the layout has the property android:clickable="true"
The proper way to do the color change is to use a background drawable xml with a pressed and normal state. If you do this in code, use getActionMasked() instead of getAction()
Return false so so that your OnTouchListener doesn't consumed the event, so the clicklistener will work..
relative3.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View arg0, MotionEvent event)
{
if(event.getAction()==MotionEvent.ACTION_DOWN )
{
relative3.setBackgroundColor(getResources().getColor(R.color.tran_grey));
}
if((event.getAction()==MotionEvent.ACTION_UP || event.getAction()==MotionEvent.ACTION_CANCEL))
{
relative3.setBackgroundColor(getResources().getColor(android.R.color.transparent));
}
// change to false.
return false;
}
});
More info : http://developer.android.com/reference/android/view/View.OnTouchListener.html#onTouch(android.view.View, android.view.MotionEvent)
You need to return false in the onTouch method which tells the OnTouchListener that the click has not been consumed. Afterwards, it forwards the click event to onClick method of OnClickListener.
I have a scrollView with lot of elements
ScrollView scroller = (ScrollView)findViewById(R.id.scrollView);
I need to attach an onClickListener to the scrollview so I do
scroller.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// This is all you need to do to 3D flip
AnimationFactory.flipTransition(viewAnimator, FlipDirection.LEFT_RIGHT);
}
});
But this is not getting triggered when I touch. Any Ideas?
The best solution seem to put LinearLayout into ScrollView and set the setOnClickListener on it.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myLayout"
android:clickable="true"
android:orientation="vertical">
<!-- content here -->
</LinearLayout>
</ScrollView>
in the Activity :
LinearLayout lin = (LinearLayout) fragment.rootView.findViewById(R.id.myLayout);
lin.setOnTouchListener(new setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Whatever
}
});
You need to set the setOnClickListener directly on the ScrollView's child.
Since a ScrollView can have only one child, you can simply use this approach:
ScrollView scrollView = //...
View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
// ...
}
//Set the onClickListener directly on the ScrollView's child
scrollView.getChildAt(0).setOnClickListener(mOnClickListener);
It is because the child of the ScrollView is getting the touch event of the user and not the ScrollView. You must set android:clickable="false" attribute to each and every child of the ScrollView for the onClickListener to work on ScrollView.
Or else the alternate could be to set the onClickListener on each of the ScrollView's children and handle it.
UPDATE 22/12/2020
sadly this also triggers after each scroll event.
This the actually the answer to the question without any odd cases by using View.OnTouchListener instead of View.OnClickListener on the ScrollView and detecting the MotionEvent.ACTION_UP where the finger is left off the screen.
To make sure that it's not a scroll, then save previous touched screen x, y values of the MotionEvent.ACTION_DOWN and compare it to those of MotionEvent.ACTION_UP. If they are not equal then certainly the user is moving their finger (i.e. scrolling) before they left it off the screen.
int mXOld, mYOld; // field values to save the tap down on the ScrollView
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mXOld = x;
mYOld = y;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (x == mXOld || y == mYOld) { // detecting it's not a horizontal/vertical scrolling in ScrollView
// HERE add the code you need when the ScrollView is clicked
Toast.makeText(MainActivity.this, "Click", Toast.LENGTH_SHORT).show();
return false;
}
}
return false;
}
});
Original Answer: Odd case that is different than the question
My problem was somehow different, so I wanted to share it..
I have a ScrollView that I have to use match_parent in its width & height; and I have an internal TextView that is centered in the ScrollView.
The text of the TextView can be long so it occupies the full height of the ScrollView, and sometimes it can be short, so there will be blank areas on the top and bottom., So setting the OnClickListener on the TextView didn't help me whenever the text is short as I want the blank areas detects the click event as well; and also the OnClickListener on the ScrollView doesn't work..
So, I solved this by setting OnTouchListener on the ScrollView and put code into MotionEvent.ACTION_UP So it can kind of simulating complete tap by lefting off the finger off the screen.
private View.OnTouchListener mScrollViewTouchListener = new View.OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
// DO Something HERE...
}
return false;
}
};
As #Zain pointed out, sometimes it is necessary to capture OnClicks for the whole area of the Scrollview, while the childs may be smaller or invisible.
To circumvent scrolling detected as an onClick, we used a GestureDetector:
final protected GestureDetector gestureDetector = new GestureDetector(getActivity(),
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
in onCreateView
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(gestureDetector.onTouchEvent(event)){
[do stuff]
}
return false;
}
});
I think you can custom a ScrollView, override the dispatchTouchEvent method, add add the custom onClick callback.
What's the best way to disable the touch events for all the views?
Here is a function for disabling all child views of some view group:
/**
* Enables/Disables all child views in a view group.
*
* #param viewGroup the view group
* #param enabled <code>true</code> to enable, <code>false</code> to disable
* the views.
*/
public static void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) {
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = viewGroup.getChildAt(i);
view.setEnabled(enabled);
if (view instanceof ViewGroup) {
enableDisableViewGroup((ViewGroup) view, enabled);
}
}
}
Override the dispatchTouchEvent method of the activity and like this:
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
return true;//consume
}
If you return true all touch events are disabled.
Return false to let them work normally
You could try:
your_view.setEnabled(false);
Which should disable the touch events.
alternatively you can try (thanks to Ercan):
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
return true;//consume
}
or
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!onInterceptTouchEvent()){
for(View child : children){
if(child.dispatchTouchEvent(ev))
return true;
}
}
return super.dispatchTouchEvent(ev);
}
This piece of code will basically propagate this event to the parent view, allowing the touch event, if and only if the inProgress variable is set to false.
private boolean inProgress = false;
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!inProgress)
return super.dispatchTouchEvent(ev);
return true;
}
Use this. returning true will indicate that the listener has consumed the event and android doesn't need to do anything.
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
The easiest way to do this is
private fun setInteractionDisabled(disabled : Boolean) {
if (disabled) {
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
}
What about covering a transparent view over all of your views and capturing all touch event?
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
In Kotlin:
fun View.setEnabledRecursively(enabled: Boolean) {
isEnabled = enabled
if (this is ViewGroup)
(0 until childCount).map(::getChildAt).forEach { it.setEnabledRecursively(enabled) }
}
// usage
import setEnabledRecursively
myView.setEnabledRecursively(false)
I made this method, which works perfect for me. It disables all touch events for selected view.
public static void disableView(View v) {
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
disableView(child);
}
}
}
It may not be possible for the whole application. You will have to override onTouchEvent() for each view and ignore the user inputs.
Per your comment:
i just want to be able to disable the views of the current activity at some point
you seem to want to disable all touch for the current activity regardless of the view touched.
Returning true from an override of Activity.dispatchTouchEvent(MotionEvent) at the appropriate times will consume the touch and effectively accomplish this. This method is the very first in a chain of touch method calls.
In case you want to disable all the views in a specific layout, one solution is adding a cover ( a front view that fills up the whole layout ) to consume all the touch events, so that no events would be dispatched to other views in that layout.
Specifically, you first need to add a view to the layout in xml file ( note that it should be placed after all the other views ), like
<FrameLayout>
... // other views
<View
android:id="#+id/vCover"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
then, remember to set click listener to that view in your code so that it will consume touch events, like
override fun onCreate(savedInstanceState: Bundle?) {
viewBinding.vCover.setOnClickListener {}
}
That's all you need.
At the point you want to enable all the view, just gone the cover.
This worked for me, I created an empty method and called it doNothing.
public void doNothing(View view)
{
}
Then called this method from onClick event on all the objects I wanted to disable touch event. android:onClick="doNothing"
When the click or touch event is fired nothing is processed.
One more easier way could be disabling it through layout (i.e. .xml) file:
Just add
android:shouldDisableView="True"
for the view you want disable touch events.