So here is the code of simple transitioning,from top_left to bottom_right, I dont understand why I have to return false for onTouch() to work properly,
1.If I set return true, one a single touch , it sets counter from 0 to 3 , or simply adds 2 or 3 to the counter and most of the time remains at its current position.
2.If I set return false, the program runs fine and does what is written ,i.e counter++;
public class MainActivity extends AppCompatActivity {
Button b;
TextView tv;
public static int counter_button=0,counter=0;
RelativeLayout.LayoutParams old_rules;
RelativeLayout rl;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b= (Button) findViewById(R.id.b1);
tv= (TextView) findViewById(R.id.tv1);
rl= (RelativeLayout) findViewById(R.id.rl);
old_rules= (RelativeLayout.LayoutParams) b.getLayoutParams();
rl.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
my_changes_touch();
return false;
}
});
}
public void my_changes_touch(){
RelativeLayout.LayoutParams rules= new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
if(counter%2==0) {
counter++;
tv.setText(" "+counter);
rules.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
rules.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
b.setLayoutParams(rules);
rules.height=400;
rules.width=400;
b.setLayoutParams(rules);
getContentTransitionManager().beginDelayedTransition(rl);
} else {
counter++;
tv.setText(" "+counter);
b.setLayoutParams(old_rules);
getContentTransitionManager().beginDelayedTransition(rl);
}
}
}
The return value determines the event is consumed by the view or not.
So true means that you are interested in other events also.
If you return false then the touch event will be passed to the next View further up in the view hierarchy and you will not receive any further calls.
Please check this answer
https://stackoverflow.com/a/3756619/2783541
Related
I have an overlay on my screen which will show some buttons to control the feature. This overlay will have a dynamic list of buttons which will be created based on the number of steps. Example if steps are 3 then 3 button will get created. I have created a LinearLayout inside this buttons will get created. I have created a method which will set all the button attributes, but somehow it's giving me null pointer exception.
In onCreateView I have initialize the buttonArray.
Here is my fragment:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mContext = getActivity();
gc = GlobalClass.getInstance(mContext);
db = DataBaseHelper.getInstance(mContext);
sectionButtons = new Button[3];
/*if(savedInstanceState!=null)
mVisible = savedInstanceState.getBoolean("visible",false);*/
manager = SharedPreferenceManager.getInstance(mContext);
//check wether to play video in cover mode or another mode
inflater.inflate(R.layout.fragment_video_side_by_side, container, false);
}
and onViewCreated() I am calling my method addSections():
// show overlay with buttons in onTouch
parentLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!mVisible) {
overLay.setVisibility(View.VISIBLE);
addSections(3);
mVisible = true;
} else {
overLay.setVisibility(View.GONE);
mVisible = false;
}
}
return true;
}
});
Method:
public void addSections(int numOfSection){
if(numOfSection==0)
return;
else {
for (int i = 0; i < numOfSection; i++) {
//set the properties for button
sectionButtons[i].setLayoutParams(new LinearLayout.LayoutParams(50, 50));
sectionButtons[i].setBackgroundResource(R.drawable.round_button);
sectionButtons[i].setText("Section "+i+"");
sectionButtons[i].setId(i);
//add button to the layout
mSectionLayout.addView(sectionButtons[i]);
}
}
}
mSectionLayout is my parent LinearLayout. While debugging I found my sectionButtons is not showing null but while setting the attributes it's throwing nullPointer exception.
Create Dynamic Buttons and attach with the Layout
You can easily create the dynamic button by the following way:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
TextView textView = new TextView(this);
textView.setText("Text View ");
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
layout.addView(textView, p);
Button buttonView = new Button(this);
buttonView.setText("Button");
buttonView.setOnClickListener(mThisButtonListener);
layout.addView(buttonView, p);
}
private OnClickListener mThisButtonListener = new OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Hello !",
Toast.LENGTH_LONG).show();
}
};
}
Using this code, you easily generate a list of buttons on the layout.
Happy coding
I have a Button, TextView(number) and an ImageView. Every time I press the button the number will increment. It will increment a lot faster when I hold the button.
I want to show an image at a specific number using ImageView at the same time making the button visible to INVISIBLE for a while to stop the increment.
The problem: If I press the button one click at a time then the below code functions well but as I hold down the button, the image appears for a very short while and continue with the numbers. And although the button is set invisible for 5 seconds, the numbers still increases(as the button is still hold).
MAIN CLASS
public class MainActivity extends AppCompatActivity {
Button button;
TextView textView;
ImageView imageView;
int i=0;
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView=findViewById(R.id.imageView);
textView=findViewById(R.id.textView);
button = findViewById(R.id.button);
button.setOnTouchListener(new RepeatListener(400, 100, new View.OnClickListener() {
#Override
public void onClick(View view) {
setText();
setImage();
}
}));
}
public void setText(){
imageView.setVisibility(View.INVISIBLE);
textView.setText(""+i);
i++;
}
public void setImage(){
if(i==10){
imageView.setImageResource(R.drawable.kitten);
imageView.setVisibility(View.VISIBLE);
buttonInvi();
}
}
public void buttonInvi(){
button.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button.setVisibility(View.VISIBLE);
}
}, 5000); // where 1000 is equal to 1 sec (1 * 1000)
}
}
RepeatListener CLASS
public class RepeatListener implements OnTouchListener {
private Handler handler = new Handler();
private int initialInterval;
private final int normalInterval;
private final OnClickListener clickListener;
private View touchedView;
private Runnable handlerRunnable = new Runnable() {
#Override
public void run() {
if(touchedView.isEnabled()) {
handler.postDelayed(this, normalInterval);
clickListener.onClick(touchedView);
} else {
// if the view was disabled by the clickListener, remove the callback
handler.removeCallbacks(handlerRunnable);
touchedView.setPressed(false);
touchedView = null;
}
}
};
public RepeatListener(int initialInterval, int normalInterval,
OnClickListener clickListener) {
if (clickListener == null)
throw new IllegalArgumentException("null runnable");
if (initialInterval < 0 || normalInterval < 0)
throw new IllegalArgumentException("negative interval");
this.initialInterval = initialInterval;
this.normalInterval = normalInterval;
this.clickListener = clickListener;
}
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.removeCallbacks(handlerRunnable);
handler.postDelayed(handlerRunnable, initialInterval);
touchedView = view;
touchedView.setPressed(true);
clickListener.onClick(view);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handler.removeCallbacks(handlerRunnable);
touchedView.setPressed(false);
touchedView = null;
return true;
}
return false;
}
}
How about checking the visibility before increasing the counter
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
if(view.getVisibility() == View.VISIBLE){
handler.removeCallbacks(handlerRunnable);
handler.postDelayed(handlerRunnable, initialInterval);
touchedView = view;
touchedView.setPressed(true);
clickListener.onClick(view);
}
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if(view.getVisibility() == View.VISIBLE){
handler.removeCallbacks(handlerRunnable);
touchedView.setPressed(false);
touchedView = null;
}
return true;
}
return false;
}
Try this line
button.setVisibility(View.GONE);
instead of
button.setVisibility(View.INVISIBLE);
Just set your listener to null when you reach a specific number and show imageview and make button invisible then after 5 seconds again set your listener and make button visible
This question already has answers here:
Android - Detect End of Long Press
(4 answers)
Closed 4 years ago.
I would like to detect when a button is not clicked. For instance, in the code above, I would like to replace the ????? with a condition indicating that the imageview is still being clicked and quit the loop as soon as the imageview is not long clicked anymore. Do you have an idea?
imageView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
while(?????)
{
int number =(Integer.parseInt(hours.getText().toString())+1)%24;
String text_number= String.valueOf(number);
if(number>-1 && number<10)
{
text_number="0"+text_number;
}
hours.setText(text_number);
}
return true;
}
});
Use View.OnTouchListener.
Example: https://stackoverflow.com/a/39588668/4586742
You will get onTouch callback with different events.
MotionEvent.ACTION_DOWN: when the user starts pressing the view.
MotionEvent.ACTION_UP: when the user stops pressing the view.
What i get from your question and proposed answer for you.
`
public class Main2Activity extends AppCompatActivity {
private boolean isImageViewBeingClicked = true;
private boolean isLongPressed = false;
private ImageView imageView;
private TextView hours;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
imageView = (ImageView) findViewById(R.id.imageView);
hours = (TextView) findViewById(R.id.textView);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
while (isImageViewBeingClicked) {
int number = (Integer.parseInt(hours.getText().toString()) + 1) % 24;
String text_number = String.valueOf(number);
if (number > -1 && number < 10) {
text_number = "0" + text_number;
}
hours.setText(text_number);
}
}
});
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
if (isLongPressed) {
isImageViewBeingClicked = false;
}
}
return false;
}
});
imageView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
isLongPressed = true;
return false;
}
});
}
}
`
In an Android app, I want to handle clicks both on a background element and on foreground elements. In my test case, clicks on the foreground elements do not get sent.
I've taken a barebones Hello World project called Test, and altered it as follows.
In activity_test.xml, I have set ids for the layout and the TextView, and I have given them both onClick properties:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
android:id="#+id/layout"
android:onClick="doStuff">
<TextView
...
android:id="#+id/hello_world"
android:textSize="52dp"
android:onClick="doStuff" />
</RelativeLayout>
In the main TestActivity class, I have the following class:
public class TestActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
TextView view = (TextView) findViewById(R.id.hello_world);
doStuff(view);
Log.d("onCreate", "testing " + view.getId());
}
public void doStuff(TextView textView) {
Log.d("test", "text " + textView.getId() + " " + R.id.hello_world);
}
public void doStuff(View view) {
Log.d("test", "view " + view.getId() + " " + R.id.layout);
}
}
In the log window, after launching the app, I see the following:
D/test﹕ text 2131165250 2131165250
D/onCreate﹕ testing 2131165250
This shows that the TestView version of the doStuff method is definitely triggered when a TestView parameter is sent.
However, if I now tap on the Hello World TextView, this is the line that is added to the log:
D/test﹕ view 2131165249 2131165249
In other words, tapping the Hello World text has the same effect as tapping on the background itself. What do I need to do to get the TextView element to respond to its onClick setting?
What you're missing is:
android:clickable="true"
The TextView is not clickable by default.
hi can you use setOnTouchListener? then you can refer below given code.. it may work i think..
as per my knowledg, the problem is , whenever you touch textview, it will call onTouchListener for both textview and background.. sorry for my bad english
private int textViesTouchStatus = 0;//public variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView view = (TextView) findViewById(R.id.textView1);
view.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
textViesTouchStatus = 1;
Log.d("touch_textview", "code that should be run on textview touch goes here");
return false;
}
});
RelativeLayout layout = (RelativeLayout) findViewById(R.id.lay);
layout.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if (textViesTouchStatus == 1)
textViesTouchStatus = 0;
else
Log.d("touch_background", "code that should be run on layout touch goes here");
return false;
}
});
I am having weird problems with Android GridView. I create a 3x4 grid and insert buttons into that grid. I want the background of the button to change when the user clicks that button. And this is working just fine for all buttons except the first one (the one with index 0 - top left). OnClick event listener doesn't fire at all for that button no matter what I do.
Here is the code where I create the view:
public View getView(int position, View convertView, ViewGroup parent) {
Button imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
Log.w("NOVO", "narejena nova celica");
imageView = new Button(mContext);
imageView.setPadding(8, 8, 8, 8);
} else {
Log.w("STARO", "stara celica");
imageView = (Button) convertView;
}
imageView.setEnabled(true);
int visina = parent.getHeight();
int sirina = parent.getWidth();
float dip = mContext.getResources().getDisplayMetrics().density;
float margin = 10*dip;
int view_height = (int)(visina - 3*margin)/4;
int view_width = (int)(sirina - 2*margin)/3;
int view_dim = 0;
if (view_height <= view_width)
view_dim = view_height;
else
view_dim = view_width;
imageView.setLayoutParams(new GridView.LayoutParams(view_dim, view_dim));
imageView.setId(position);
imageView.setOnClickListener(celice.get(position));
/*imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Toast toast = Toast.makeText(mContext, v.getId() + "bla", Toast.LENGTH_SHORT);
//toast.show();
celice.get(v.getId()).celicaVisible(4000);
}});*/
celice.get(position).id = position;
celice.get(position).setButton(imageView);
return imageView;
}
If I replace
imageView = (Button) convertView;
with
imageView = new Button(mContext);
then the onClick() gets fired but the background still doesn't change. All the other buttons are working as expected.
And here is the custom class "Celica" that takes care of the actual work - changing the background...
public class Celica implements OnClickListener {
public boolean odkrit;
public boolean najden;
public int id;
public Drawable slikca1, slikca2;
public Celica par;
private Timer tim;
public Button but;
public Context con;
static int buttonsVisible = 0;
Celica(Drawable s1, Drawable s2) {
this.slikca1 = s1;
this.slikca2 = s2;
}
void celicaVisible(int millis) {
if (odkrit)
return;
Log.w("TEST", "prizganih " + buttonsVisible);
if (buttonsVisible >= 2)
return;
odkrit = true;
buttonsVisible++;
tim = new Timer();
tim.schedule(new timerDone(), millis);
((Activity)con).runOnUiThread(new Runnable() {
#Override
public void run() {
but.setBackground(slikca2);
}
});
}
void setButton(Button b) {
but = b;
((Activity)con).runOnUiThread(new Runnable() {
#Override
public void run() {
but.setBackground(slikca1);
}
});
}
class timerDone extends TimerTask {
#Override
public void run() {
if (!najden) {
odkrit = false;
((Activity)con).runOnUiThread(new Runnable() {
#Override
public void run() {
but.setBackground(slikca1);
}
});
}
buttonsVisible--;
tim.cancel();
}
}
#Override
public void onClick(View v) {
celicaVisible(4000);
}
}
In Android, ID of any View must be non zero and non negative number. means View ID should be > 0. and there is problem, when you are setting ID to the Button like
imageView.setId(position)
here ID of a button will be zero when position is zero(means first item). may be due to this, First Button's OnClickListener is not getting fired...try setting a ID that is greater than zero to Button and try once...
you can write like
imageView.setId(position+1) to ensure ID > 0
I actually figured it out. Everything works if I use the view that gets provided by the onClick() method instead of saving the actual button at the creation of the Celica object.
So basically adding:
but = (Button) v;
to the onClick() method solved the problem.