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;
}
});
Related
I have ScreenRecorder activity invoking RecorderService. RecorderService setting floating view with imageview. when i onclick on image view ScreenRecorder oncreate got called not able to invoke onclick action. But OnTouchListener working fine
<ImageView
android:id="#+id/sr_float_home"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="8dp"
android:src="#drawable/recorder"
android:onClick="startRecord"
tools:ignore="ContentDescription"/>
ScreenRecorder activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate " );
mProjectionManager = (MediaProjectionManager)
getSystemService(Context.MEDIA_PROJECTION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
} else {
recordeScreen();
}
Log.d(TAG,"onCreate end");
}
private void recordeScreen() {
Log.d(TAG, "recordeScreen open " );
if (mMediaProjection == null) {
startService(new Intent(ScreenRecorder.this, RecorderService.class));
finish();
return;
}
Log.d(TAG, "recordeScreen open end " );
}
public void startRecord(){
Log.d(TAG, "startRecord start " );
startActivityForResult(mProjectionManager.createScreenCaptureIntent(),
PERMISSION_CODE_SR);
Log.d(TAG, "startRecord end " );
finish();
return;}
RecorderService
#Override
public void onCreate() {
super.onCreate();
mChatHeadView = LayoutInflater.from(this).inflate(R.layout.activity_screen_recorder, null);
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mChatHeadView, params);
final ImageView srFloatHome = (ImageView)
mChatHeadView.findViewById(R.id.sr_float_home);
srFloatHome.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
}
}
}
i have also tried placing startRecord method like ontouch , but still not working. can someone please tell me why onclick call not received insteated it calling activity oncreate.
Seems like you're missing the parameter on your startRecord function. From Android documentation:
public static final int onClick
Name of the method in this View's context to invoke when the view is clicked. This name must correspond to a public method that takes exactly one parameter of type View. For instance, if you specify android:onClick="sayHello", you must declare a public void sayHello(View v) method of your context (typically, your Activity)
Maybe your code less a property in xml.
android:clickable="true"
if you want ImageView have the clicked method ,should add this,
this is demo code .xml:
<ImageView
android:id="#+id/image"
android:layout_width="100dp"
android:layout_height="200dp"
android:background="#android:color/background_dark"
android:onClick="StartDoSomething"
android:clickable="true"/>
and in .java is
public void ButtonClick(View v){
System.out.println("Do something here!");
}
hope to help you.
I have used layout root element and used below code i am able to get onclick in recorderervices
mChatHeadView.findViewById(R.id.sr_float_home);
form
final View srFloatHome = mChatHeadView.findViewById(R.id.sr_head_root);
srFloatHome.setOnClickListener(this);
my onclick method in RecorderService
public void startRecord(View v){}
I have actually read several answers to this but they are so different than the simple way I am implementing click responses that I am wondering if there is a way to add something simple to what I am doing to create an onLongClick responas.
Basically, all my XML code is written with statements like this:
android:onClick="onSync"
Then my Java has:
public void onSync(View v) {
...
Toast toast3=Toast.makeText(this, "Sync was pressed",Toast.LENGTH_SHORT);
toast3.show();
}
What I would like to do is have a different function that is called when the button gets a long press. Right now, a long press causes the same action as a short press.
Specifically, I would like to know how to interface to a routine such as this:
public void onSyncLong(View v) {
...
Toast toast3=Toast.makeText(this, "Long Sync was pressed",Toast.LENGTH_SHORT);
toast3.show();
}
I would certainly appreciate any help on this problem. It would be great if the reply told me what to do in the XML and in the Jave. Thanks so much.
----------------------------UPDATE------------------------
Here is my onCreate code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.start_meters);
textLL = (TextView)findViewById(R.id.textLL);
textTimer = (TextView)findViewById(R.id.textTimer);
textTimeToLine = (TextView)findViewById(R.id.textTimeToLine);
Button button = (Button) findViewById(R.id.button_sync);
button.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
return true;
}
});
}
And here is the button XML segment
<Button
android:id="#+id/buttonSync"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Gun/Sync"
android:onClick="onSync"
android:textSize="#dimen/font_small"
android:background="#drawable/round_button"
android:padding="3sp"
android:longClickable="true"/>
------------Final Update----------------
Here is the working code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.start_meters);
textLL = (TextView)findViewById(R.id.textLL);
textTimer = (TextView)findViewById(R.id.textTimer);
textTimeToLine = (TextView)findViewById(R.id.textTimeToLine);
Button button = (Button) findViewById(R.id.buttonSync);
button.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
StartLine2.startTime = pTime + 1000*60*5;
return true;
}
});
}
You can't do this via XML. Instead, use:
Button button = (Button) findViewById(R.id.<your_id>);
button.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
return true;
}
});
Make sure this code comes after setContentView() has been called.
Also, make sure that the android:longClickable property is set to true.
In your XML, the ID is set to buttonSync, while in the Java code you're using button_sync. This is the reason for your NullPointerException, as you don't have a button called button_sync.
public class GameScoreFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.v("TTT", "GameScoreFragment.OnCreateView()");
View viewScore = inflater.inflate(R.layout.gamescorelayout, container, false);
// set onLongClick listeners for both buttons
// when player long presses any of the two buttons, scores are reset
Button tempButton = (Button) viewScore.findViewById(R.id.id_button_pone_score);
tempButton.setOnLongClickListener( mLongListener );
tempButton = (Button) viewScore.findViewById(R.id.id_button_ptwo_score);
tempButton.setOnLongClickListener( mLongListener );
return viewScore;
}
// define a variable mLongListener to hold the listener code
// and then use mLongListener to set the listener
// if we don't define the variable, then we will have to write the listener code at two places (once for each button)
private View.OnLongClickListener mLongListener = new View.OnLongClickListener() {
#Override
public boolean onLongClick(View pView) {
//reset player scores
GameFragment tempGameFragment = (GameFragment) getFragmentManager().findFragmentById(R.id.id_gamefragment);
if (tempGameFragment != null)
tempGameFragment.resetPlayersScore(false);
return true;
}
};
}
I wrote an app with 1 activity and 1 view, so it gives me the coordinates of my fingers i put on the screen. Worked perfectly.
The Problem is now: I Created a new App with more than 1 Activity so i can change between them with intents. also worked fine. But one Activity should be the one wich give me my finger positions. So i Copyed the class and activity put them into the manifest. And made a Button and a intend for to run it.
So when i try to run it it creates the class but doesnt react on my onTouchEvents anymore...
and i have no clue why. i hope i explained my problem well enough for u guys to understand.
So this is my main activity. starts the menu with the option to go to the not working class
public class V1_2 extends Activity implements OnClickListener{
Button btn_1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_v1_2);
btn_1 = (Button) findViewById(R.id.button1);
btn_1.setOnClickListener(this);
}
public void onClick(View v) {
if( btn_1.getId() == ((Button)v).getId() ){
startActivity(new Intent(this,Obj_recog.class));
}
}
This is now the activity wich creates the touchpiont class for the touchevents
public class Obj_recog extends Activity implements OnClickListener{
touchtest TP;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blank);
TP = new touchtest(this);
}
public void onClick(View v) {
}
And now an example of what doesnt work here but worked at the last project the same way
public class touchtest extends View{
public touchtest(Context context) {
super(context);
Log.d("worked", "worked");
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
Log.d("Touch", "TOUCH!!!!");
return true;
}
}
So i get the message that it "worked" but it doesnt react on touchevents like it used to do...
It will be worked if you add touchtest view as your main view by using setcontentview and then
add touchlistener on that view and call your ontouchevent from your touchtest class. code will be like --
TP = new touchtest(this);
setContentView(TP);
TP.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
TP.onTouchEvent(event);
return false;
}
});
i think should change this approach find an alternative way to implement for which you are going in this way.
In this way you can keep your blank layout and also TP.
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
TP = new touchtest(this);
rl.addView(TP);
TP.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
TP.onTouchEvent(event);
return false;
}
});
I'am developing a sample android application to learn about drag & drop in android. On start of the app, i'am displaying few images on a grid view. Now i need to drag one image at a time over to the place of another. After dropping an image over another, the images should swap its places. How can i achieve it ? Please guide/help me.
You can easily achieve this by using thquinn's DraggableGridView
You can add your custom layout
public class DraggableGridViewSampleActivity extends Activity {
static Random random = new Random();
static String[] words = "the of and a to in is be that was he for it with as his I on have at by not they this had are but from or she an which you one we all were her would there their will when who him been has more if no out do so can what up said about other into than its time only could new them man some these then two first may any like now my such make over our even most me state after also made many did must before back see through way where get much go well your know should down work year because come people just say each those take day good how long Mr own too little use US very great still men here life both between old under last never place same another think house while high right might came off find states since used give against three himself look few general hand school part small American home during number again Mrs around thought went without however govern don't does got public United point end become head once course fact upon need system set every war put form water took".split(" ");
DraggableGridView dgv;
Button button1, button2;
ArrayList<String> poem = new ArrayList<String>();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
dgv = ((DraggableGridView)findViewById(R.id.vgv));
button1 = ((Button)findViewById(R.id.button1));
button2 = ((Button)findViewById(R.id.button2));
setListeners();
}
private void setListeners()
{
dgv.setOnRearrangeListener(new OnRearrangeListener() {
public void onRearrange(int oldIndex, int newIndex) {
String word = poem.remove(oldIndex);
if (oldIndex < newIndex)
poem.add(newIndex, word);
else
poem.add(newIndex, word);
}
});
dgv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
Toast.makeText(getApplicationContext(), "On clicked" +position, Toast.LENGTH_SHORT).show();
dgv.removeViewAt(position);
poem.remove(position);
}
});
button1.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
String word = words[random.nextInt(words.length)];
addView();
poem.add(word);
}
});
button2.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
String finishedPoem = "";
for (String s : poem)
finishedPoem += s + " ";
new AlertDialog.Builder(DraggableGridViewSampleActivity.this)
.setTitle("Here's your poem!")
.setMessage(finishedPoem).show();
}
});
}
public void addView()
{
LayoutParams mLayoutParams= new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
LinearLayout mLinearLayout= new LinearLayout(DraggableGridViewSampleActivity.this);
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
mLinearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
ImageView mImageView = new ImageView(DraggableGridViewSampleActivity.this);
if(dgv.getChildCount()%2==0)
mImageView.setImageResource(R.drawable.child1);
else
mImageView.setImageResource(R.drawable.child2);
mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
mImageView.setLayoutParams(mLayoutParams);
mImageView.setId(dgv.getChildCount());
mImageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), v.getId()+"clicked ", Toast.LENGTH_SHORT).show();
return dgv.onTouch(v, event);
}
});
TextView mTextView = new TextView(DraggableGridViewSampleActivity.this);
mTextView.setLayoutParams(mLayoutParams);
mTextView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), v.getId()+"clicked text ", Toast.LENGTH_SHORT).show();
return dgv.onTouch(v, event);
}
});
TextView mTextViewLabel = new TextView(DraggableGridViewSampleActivity.this);
mTextViewLabel.setText(((dgv.getChildCount()+1)+""));
mTextViewLabel.setLayoutParams(mLayoutParams);
mTextViewLabel.setId(dgv.getChildCount());
mTextViewLabel.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(getApplicationContext(), v.getId()+"clicked text ", Toast.LENGTH_SHORT).show();
return dgv.onTouch(v, event);
}
});
mLinearLayout.setTag(mTextViewLabel);
mLinearLayout.addView(mTextViewLabel);
mLinearLayout.addView(mImageView);
mLinearLayout.addView(mTextView);
dgv.addView(mLinearLayout);
}
}
I'm a beginner in android and at the moment, I'm working on simple app. I have 7 pictures and I want to change one-by-one when user touches the screen. Here's my code, my app crashes on the second touch on the screen. If anyone can help, I'd be thankful.
public class Game extends Activity {
public TextView result;
public ImageView pirveli, meore, mesame, meotxe, mexute, meeqvse, meshvide;
int counter=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
result = (TextView) findViewById(R.id.result);
result.setText("Number of steps made: " + counter);
pirveli = (ImageView) findViewById(R.drawable.pirveli);
meore = (ImageView) findViewById(R.drawable.meore);
mesame = (ImageView) findViewById(R.drawable.mesame);
meotxe = (ImageView) findViewById(R.drawable.meotxe);
mexute = (ImageView) findViewById(R.drawable.mexute);
meeqvse = (ImageView) findViewById(R.drawable.meeqvse);
meshvide= (ImageView) findViewById(R.drawable.meshvide);
}
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction()==0){
result.setText("Number of steps made: " + counter);
counter++;
pirveli.setImageResource(R.drawable.meore);
}
return false;
}
AND one more question: when I touch the screen the first time, int counter isn't increasing. how can i fix it?
Assuming R.drawable.meore, R.drawable.mesame, etc. are drawable resources in your drawable folder, this should work.
public class Game extends Activity {
TextView result;
int[] drawableIds = {R.drawable.meore, R.drawablemeSame, R.drawable.meotxe, R.drawable.mexute, R.drawable.meeqvse, R.drawable.meshvide};
int counter=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
result = (TextView) findViewById(R.id.result);
result.setText("Number of steps made: " + counter);
pirveli = (ImageView) findViewById(R.drawable.pirveli);
pirveli.setOnTouchListener(this);
}
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
result.setText("Number of steps made: " + counter);
counter++;
pirveli.setImageResource( drawableIds[ drawableIds.length % counter ] );
}
return false;
}
Here, it will cycle through the resource Id's and change the ImageView every time the user touches it.
First of all you should use the MotionEvent constants as they could change in future API versions, also you need to return true after a touch event is handled.
I also suggest you add null checks for good measure.
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
if (result != null);
result.setText("Number of steps made: " + counter);
counter++;
if (pirveli != null)
pirveli.setImageResource(R.drawable.meore);
return true;
}
return false;
}
A stack trace would be of much assistance if none of those are your problems.