I need to have both on a TextView:
When the TextView is clicked, trigger a function. But when a certain part of the text is clicked, trigger a different function.
So I have a ClickableSpan for that certain part, and an OnTouchListener on the whole TextView:
SpannableString string = new SpannableString(input);
// ...
string.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
functionOne();
}
}, start, i, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(string);
// ...
textView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
Both work fine for themselves:
If I do not add the OnTouchListener, it calls functionOne(), triggered from the ClickableSpan.
But if I also add the OnTouchListener, it only calls gestureDetector.onTouchEvent(event). Also if I click on the certain part of the text, where the ClickableSpan should be triggered.
How can I have both?
So that if the certain part is clicked, the ClickableSpan is triggered, and if a different part of the text is clicked, then gestureDetector.onTouchEvent(event) is called.
Try this below function to achieve clickable span and there is no need to call touch listener. click event will be handled by ClickableSpan.
fun setClickableSpan(
spannable: Spannable,
paths: ArrayList<String>,
listener: EventListener
) {
for (i in paths.indices) {
val indexOfPath = spannable.toString().indexOf(paths[i])
if (indexOfPath == -1) {
continue
}
val clickableSpan: ClickableSpan = object : ClickableSpan() {
override fun onClick(textView: View) {
listener.onItemClick(textView, i, paths[i])
}
}
spannable.setSpan(
clickableSpan, indexOfPath,
indexOfPath + paths[i].length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
Related
This question already has answers here:
Android : How to set onClick event for Button in List item of ListView
(10 answers)
Closed 4 years ago.
I'm making an inventory tracker app for Android for a practice project. I use SQLite for the storage and my ListView displays the contents of the database using a CursorAdapter. I use CursorLoader to fetch the data from the database
Each row in my ListView has a couple of TextViews and a Button. I plan to use the Button to decrement the quantity column/property of the selected item in the database.
Where do I setup the button OnClick listener? In my Activity class or my CursorAdapter class' bindView()?
Also how can I detect which row the button was pressed on from the button click?
I've already used the ListView's onItemClickListener to send the user to a detailed Activity that display more info about the current row. That had an id argument that gets passed. So I'm finding an equivalent that I can use for the buttons I put on each row.
Look the following. I used the Custom adapter to add the onItemClickListener:
private class MyListAdapter(val ctx: Context, val values: List<MyListInformatin>) : ArrayAdapter<MyListInformatin>(ctx, -1, values) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val rowView = inflater.inflate(R.layout.item_my_layout, parent, false)
rowView.setOnClickListener {
val detailsActivity = Intent(ctx, DetailsActivity::class.java)
detailsActivity.putExtra(DetailsActivity.ROUTE_NUMBER_PARAM, values.get(position).routeNumber)
val bundle = Bundle()
bundle.putParcelable(detailsActivity.ROUTE_NO_STRUCTURE_PARAM, values.get(position).strucutre)
detailsActivity.putExtra(detailsActivity.PARAM_BUNDLE, bundle)
ctx.startActivity(detailsActivity)
}
return rowView
}
}
You can create an interface inside your adapter and a declare a fucntion in this interfae like ** void itemClick(int position)** and implement that interface in your activity
for void itemClick(int position) method :- Define it on
holder.setOnClickListener() block like -
viewHolder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (yourInterface != null) {
yourInterface.itemClick(position);
}
}
});
For detailed description refer the below link -
https://www.c-sharpcorner.com/UploadFile/9e8439/create-custom-listener-on-button-in-listitem-listview-in-a/
This question has been answered already, you need to setup your list items as not clickable and manually listen for onClick events of buttons, see a detailed answer here: Android : How to set onClick event for Button in List item of ListView
public class MyCustomAdapter extend Adapter {
private MyOnClickListener mListener;
#Override
public View getView(int position, View view, ViewGroup parent)
{
...
// Your view
mContainer.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mListener.onWholeItemClick(position);
}
});
// Your button
mButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mListener.onButtonClick(position);
}
});
}
public void setListener(MyOnClickListener listener) {
this.mListener = listener;
}
// Listener interface
public interface MyOnClickListener() {
void onWholeItemClick(int position); // Can pass data as a parametter
void onButtonClick(int position);
}
}
public class MyActivity extend Activity implement MyOnClickListener() {
...
#Override
public void onCreate(...) {
mAdapter = new MyCustomAdapter(this);
mAdapter.setListener(this); // Pass the listener to adapter
}
#Override
public void onWholeItemClick(int position) {
//
}
#Override
public void onButtonClick(int position) {
//
}
}
That how you can fully hanhle click events
In onBindViewHolder give a tag to that button. that tag can be the position of item or the item itself . ( tag can be object )
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
CUSTOMMODEL item = items[position];
...
holder.button.setTag(item);
//OR
holder.button.setTag(position);
...
holder.button.setOnClickListener(clickListener);
}
in your onClick(View view) method, get tag from the view and you can understand which item is clicked.
How to disable onClick when I click for LongClick?
It's a code from recyclerView, when I try long click I just see that normal click just spamming like hell.
holder.title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "To clear your recomendations, press for few seconds. ", Toast.LENGTH_SHORT).show();
}
});
holder.title.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
clearPreferences(R.string.preferences_reminder);
Toast.makeText(context, "Recomendations cleared.", Toast.LENGTH_SHORT).show();
return true;
}
});
In case if there is necessity to listen both onLongClick and onClick,
Here is another approach:
Example:
#Override
public boolean onLongClick(View view) {
//return value true to make sure only onLongClick is executed without triggering normal onClick
return true; // or false
}
return true means that the event is consumed. It is handled. No other click events will be notified.
return false means the event is not consumed. Any other click events will continue to receive notifications.
So to make sure both onClick and onLongClick are not triggered at the same time, return true from onLongClick event.
Add this line
holder.title.setOnClickListener(null);
I want to change the background color of button, on button click, this code is not showing any error , neither it is working .
capstone.setOnClickListener(new HandleClick());
}
private class HandleClick implements View.OnClickListener{
#Override
public void onClick(View v) {
Button btn = (Button) v;
String text = btn.getText().toString();
btn.setBackgroundResource(R.color.btnClick);
Log.d("color", R.color.btBackground + ""); // D/color: 2131427344
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT);
toast.show();
}
}
The Log.d() shows the value of color, but the color of button does not changed.
setBackgroundResource(int) method is waiting for a drawable object. If you'd like to use colors, use the appropriate method which is setBackgroundColor(int)
and call btn.invalidate(); after that
More details on Android Developers
http://developer.android.com/reference/android/view/View.html#setBackgroundResource(int)
If you need to use a color resource as the background color of a view, you will need to get the ARGB color from resources using getColor(), then set that in setBackgroundColor().
btn.setBackgroundColor(getResources().getColor(R.color.btBackground, null));
The function setBackgroundResource will render the button.
try
setBackground(this.getResources().getDrawable(R.drawable.btBackground))
We can use this, as It will get the default background color when the unclick the button. Or we can use the code what I have posted in answer, the problem was I was using same color as default as well as on button click.
capstone.setOnTouchListener(new HandleTouch());
}
private class HandleTouch implements View.OnTouchListener{
#Override
public boolean onTouch(View v, MotionEvent event) {
Button btn = (Button) v;
if(event.getAction() == MotionEvent.ACTION_DOWN) {
btn.setBackgroundResource(R.color.btnClick);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
btn.setBackgroundResource(R.color.btBackground);
}
return false;
}
}
When I click an Android button the Android's Software Keys are shown (hidden before) instead of firing the onClick() method for the actual button that I click.
I have two methods for showing or hiding the system UI:
1.
// Set up the user interaction to manually show or hide the system UI.
contentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TOGGLE_ON_CLICK) {
mSystemUiHider.toggle();
} else {
mSystemUiHider.show();
}
}
});
and 2:
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
And I also have another method which a switch to get the onClick() event on buttons
public void onClick(View v) { switch() { } }
Is it possible to fix this behaviour and when I click the actual button will be fired and the System UI will be shown?
There is no workaround to overcome this behaviour until you have both touch listener and also a click listener inside the same view. Try using
View.SYSTEM_UI_FLAG_LOW_PROFILE|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
instead. Add the below code before setcontentview() method.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
decorView.setSystemUiVisibility(uiOptions);
I have ImageViews inside of a GridView, I had been using an OnItemClickListener along with an OnItemLongClickListener set on the GridView to open the image on a larger page and to delete the item respectively. Now, I have to implement rearranging of the ImageViews in the GridView, so I plan to move the deletion function to a double tap gesture, (please do not lecture me on android style guidelines (including the possibility of contextual actionbars, which I suggested), as this is what my boss asks for to emulate functions inside our ios app) in order to reserve long click for the drag and drop. I set an OnTouchListener on each view in the getView of my custom adapter, feeding a GestureDetecter with a listener extending SimpleOnGestureListener the given MotionEvent with onTouchEvent. I know what to do up to that point, but when I included (onDown of course, to get other callbacks) onDoubleTap, onSingleTapConfirmed, and onLongPressed all taps were interpreted as long clicks. And when I removed the both callback methods to be replaced with their listener counterparts once again (ie OnItemClickListeners) I received those two gestures but not the double tap, which makes sense, as double taps start out as a single tap unless you wait for a bit less than a second to confirm them as singles rather than potential doubles. I also tried placing the OnItemClickListener, but not the OnItemLongClickListener, with the callback in the extended SimpleOnGestureListener. In this case, only long presses were ever interpreted, but other gestures caused no response. Here is my code as it stands now, and do note that I returned false in the onTouchEvent in order to allow others (itemclicklisteners) to consume the events following the attempts made in the GestureDetector.
public class MainBoardGridAdapter extends GenericBoardGridAdapter implements OnItemLongClickListener {
private class Ges extends GestureDetector.SimpleOnGestureListener {
int pos;
public Ges(View v) {
pos = (Integer) v.getTag();
}
#Override
public boolean onDown(MotionEvent me) {
//this does get called but none of these methods below
return true;
}
#Override
public boolean onDoubleTap(MotionEvent me) {
new DeleteConfirmationPrompt(c, "board") {
#Override
protected boolean onDeleteConfirmed() {
// delete the visionboard
return deleteBoard(pos);
}
}; // Constructor shows dialog
return false;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
MainBoardGridAdapter.super.flagForUpdate(pos);
if (listener != null) {
listener.onBoardClick(pos, getName(pos));
} else {
Intent intent = new Intent(c, VisionBoardActivity.class);
intent.putExtra(VisionBoardActivity.EXTRA_VISION_BOARD_NAME, getName(pos));
frag.startActivityForResult(intent, MyBoardsFragment.REQUEST_EDIT);
}
return false;
}
}
#Override
public boolean onItemLongClick(AdapterView<?> parent, View v,
final int pos, long id) {
Toast.makeText(c, "Long", Toast.LENGTH_LONG).show();
return false;
}
// called by getView of extended adapter
#Override
public void onImageLoaded(ImageView iv, String data, View root) {
iv.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
(new GestureDetector(c, (new Ges(v)))).onTouchEvent(event);
return false;
}
});
}
}
And in the Activity, gv is my GridView:
gv.setOnItemLongClickListener(gridAdapter);
Also note that I had been using true in the return value in the GestureDetector methods, until trying the current configuration.There was no difference to be seen.
Thank you for your valuable time and help, I hope that someone will be able to point out what I am doing incorrectly.
-Jackson