I have a Main Activity that has a bunch of child views and then I have a ListView whose items are dynamically generated. I'd like to be able to long click any of these items and have this event handled in the Main Activity.
MainActivity
LinearLayout
ListView
Item - (long click here)
Now I know how to subscribe the the onLongClick event of the dynamically created ListView item itself but that's in the adapter I use to create the items.
What I was hoping was, that I could simply subscribe to the onLongClick event of the Main Activity and I'd see the event from the dynamically created ListView item propagate up to the MainActivity. But that's not happening.
My MainActivity implements View.OnLongClickListener, like so
class MainActivity : Activity(), View.OnLongClickListener {
override fun onLongClick(v: View?): Boolean {
Log.d("APP", "LongClicked: ")
return true
}
......
}
However, I'm not sure how to set the handler in the Activity itself. That is, for onClick, I would set android:onClcik="onCLick", in the XML of the Main Activity, however, I don't see an option to do the same for onLongClick
Also, I have not set any attributes such as android::longClickable="true/false"
any of the views. I'm a bit confused by the true/false and what the actually mean.
Any help would be appreciated.
UPDATE
I tried calling the setOnLongCLickListener on the ListView in the Main Activity, since I have access to the ListView there. Like so
availableZonesListView = findViewById(R.id.availableZonesListView)
availableZonesListView!!.onLongClickListener(this)
The MainActivity ('this') implements the View.OnLongClickListener and I see events coming in there when I long click directly on the MainActivity/Layout. But I don't see eventing coming in there when I long click on the items of the ListView
Now I know how to subscribe the the onLongClick event of the dynamically created ListView item itself but that's in the adapter I use to create the items.
public MainActivity extends .. implements MyClickListener {
... onCreate {
... = new MyAdapter(yourParams, this); // `this` is the new param
}
#Override
public void onAnyItemLongClicked() {
// Do whatever you want
}
}
Create your new interface:
interface MyClickListener {
void onAnyItemLongClicked();
}
Then in your adapter where you "Now I know how to subscribe the the onLongClick event". It would be something like this:
public class MyAdapter {
// other fields
private final MyClickListener listener;
public MyAdapter(otherParams, MyClickListener listener) {
.. assign other params
this.listener = listener;
}
}
// However you set your item click listener (in getView)
adapter.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public void onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
listener.onAnyItemLongClicked();
}
});
This will propagate the click event from the adapter to the activity.
(I had to improvise a bit because you didn't share many code details)
Related
In my activity I have one recyclerview and each item view contains buttons. I want to be able to change some UI elements and other things such as an Array of custom objects for the adapter itself in my activity from the recyclerview adapter. Until now I declared the needed views as static but I found out that it's a terrible practice.
Example: I have the following recyclerview that represents a cart filled with a custom viewholder, from an Array of custom "cart_product" objects. (One of this custom oject's proprieties is "quantity" - represented by the spinner). I want to be able to change the object's "quantity" property by changing the spinner's value from the adapter... How could this be done? And when all the products are removed from cart (by swiping & detected from adapter) I want to display a textvie
ScreenShot
You can use callbacks:
In adapter create an interface:
public interface EventHandler {
void handle(int position) // if u need know position. If no, just create method without params
}
Create an private instance of interface in adapter:
public class YourAdapter extends RecyclerView.Adapter<YourHolder> {
private EventHanlder handler;
}
Implement EventHanlder in activity:
public class Mainacitivity extends Activity implements YourAdapter.EventHandler {
//.....
#Override
void handle (int position) {
// TODO do whatever u want
}
}
Add EventHandler to constructor parameters:
public YourAdapter (List<YourObject> data, EventHandler handler) {
//....
this.handler = handler;
}
When you need to change UI call
handler.hanlde(position);
And, finally pass this when initializing adapter
adapter = new YourAdapter (data, this)
If u need something else (not position), just change signature of handle() method
Just wondering if what I'm trying to do is possible. So i have a custom adapter for a listview. It contains a textview and two buttons. I would like one of the listview buttons to remain hidden unless a specific button is pressed on the main activity.
So far I have the listview buttons performing their intended function but I have no idea how I would even begin to get what I'm wanting.
Sorry, for clarification, I have one button completely separate from the listview that is just always there. When I press this button I would like to toggle the visibility of a button that is on each listview item all together. The best example of this that I can think of is having a list of items and a button that can toggle off the 1. 2. 3. 4. that comes in front of each item.
Create a method in your adapter for knowing you have clicked the button from your main activity like this
public void buttonIsClicked(){ //in your adapter
buttonhide.setVisibility(visibility?View.VISIBLE:View.GONE);
}
And call this method from your activity on btnclick.
like
yourAdapter.buttonIsClicked();
and call this method for notifying the adapter about the change.
yourAdapter.notifyDatasetChanged().
or
You can use an interface for listening to the clicks in main activity and implement that listener in your adapter
Set visibility gone to the button you want to hide by calling code
buttonhide.setVisibilty(VIEW.GONE);
hide it in oncreate() of your activity and make it shown on the button click event by calling code buttonhide.setVisibilty(VIEW.VISIBLE);
Below is the code
btnView.setVisibility(View.GONE);
yes it is possible to do that.
First have a Model class to back the listview data and keep a flag in that model which indicates whether to show the button in that row's data model. On certain condition change that model's flag and call notifyDataSetChanged() on adapter.
Ex:
class Model{
String label;
boolean showBtn;
}
in adapter's getView()
Model model = list.get(position)
if(model.showBtn){
btn.setVisibility(View.VISIBLE);
}else{
btn.setVisibility(View.GONE);
}
in Activity
disableButton(){
modelList.get(0).setShowBtn(false);
adapter.notifyDataSetChanged();
}
This code will hide button in first row
Add a Boolean value in your dataset which represent the Visibility state of the button.
public class Dataset {
private boolean visible;
public boolean isVisible() {
return this.visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
//..more items
}
Then in your getView method of the Adapter check this Boolean value to show/hide the button.
boolean visibility = yourDataset.get(position).isVisible();
yourButton.setVisibility(visibility?View.VISIBLE:View.GONE);
And when the Button outside of your listview is clicked Update your dataset. And call yourAdapter.notifyDatasetChanged().
What you are attempting is: manipulating the visibility of the button declared in the Adapter from the containing activity. Simple, put a controlling variable in the activity and pass it a parameter to adapter.
Boolean mShowButton; //a controlling variable
void onCreate(Bundle savedInstanceState) {
...
mAdapter=new MyAdapter(...,mShowButton);
mButton.setOnClickListener(actionShow );
}
OnClickListener actionShow = new OnClickListener() {
#Override
public void onClick(View button) {
mShowButton=true;
mAdapter.notifyDataSetChanged();
mListView.invalidateViews();
}
};
And do this in your adapter,
Boolean showButton;
public MyAdapter(Context context, List<String> myList, Boolean showButton) {
...
this.showButton=showButton;
}
public View getView(int position, View rowView, ViewGroup parent) {
...
if(showButton){
mButtonTwo.setVisibility(View.GONE);
}else{
mButtonTwo.setVisibility(View.VISIBLE);
}
}
This is a my use case. I have an activity with a listview and a textview. The textview is the sum of all numbers on the listview, the listview has all the numbers.I have a custom adapter for this case.
On each row of the listview, I have a button. This button will change the number on this row.
what I want to do is this:
when user clicks the button, the value on each row is changed - doable.
the sum on the textview also changes accordingly.
This is a simplified example. In reality, I also have a constraint that I have a data model to represent the data on each role. I am not able to extend the data model to DataSetObserver.
any help?
You should create a listener, which listens for touch on your increment button and inside it call a method of the class extending an interface you created.
To make it easy, in your adapter you will have:
public interface OnIncrementListener{
onNumberIncremented();
}
private OnIncrementListener mListener;
//This is inside getView method of your adapter
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mListener.onNumberIncremented();
}
});
Then your activity
public class MyActivity extends Activity implements OnIncrementListener {
//inside onCreate
myAdapter.setOnIncrementListener(this);
//end onCreate
#Override
public void onNumberIncremented() {
//Change value of your TextView here
}
}
I have a Custom BaseAdapter showing a ListView containing a TextView and a CheckBox. The TextView has an OnClickListener implemented to perform a specific action when clicked on the text. Within the Adapter I have a OnCheckedChangeListener registered which keeps track of which item is checked (because of the ListView recycling).
I want to start an ActionMode when I check a CheckBox and stop it when I uncheck it.
How can I inform the main activity hosting the adapter that a check has been made?
Create a listener call back interface, something like:
public interface ListenerCheckBox
{
public void onRowChecked(int rowNun);
}
Then, make your main activity implement this listener:
public class ActivityMain implements ListenerCheckBox
Then, when you instantiate your custom BaseAdapter, pass in the listener:
//kv 3rd parameter would be listener
CustomBaseAdapter customBaseAdapter = new CustomBaseAdapter(this, items, this);
Then, in the constructor of your CustomBaseAdapter, set a member field to the listener:
public CustomBaseAdapter(Context context, ArrayList<Item> items, ListenerCheckBox listenerCheckBox)
{
mListenerCheckBox = listenerCheckBox;
...
}
Then, every time an item is checked, call:
mListenerCheckBox.onRowChecked(rowNum);
Here is a Android Studio project that shows an example of how to do what you are asking. In particular, check out the check listener and its onClick():
#Override
public void onClick(View v) {
if (mMode != null) {
mMode = mListView.startActionMode(new ExampleMultiChoiceModeListener(mActivity));
}
mListView.setItemChecked(mPosition, ((Checkable) v).isChecked());
}
I know that ListActivity gives me the possibility to use onListItemClick.
On the other hand in a normal Activity i can include multiple lists and make easy switching+animation through a ViewFlipper.
So. Can i make it work alltogether?
[Solved] Yes! ... implements are the kings. Deleted my code to minimize confusion.
Have you tried having your Activity implement OnItemClickListener and then set your lists' onItemClickListener to the activity? I.e.
public class MyActivity extends Activity implements OnItemClickListener {
...
public void onCreate(...) {
...
mList1.setOnItemClickListener(this);
mList2.setOnItemClickListener(this);
...
}
...
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
if (adapter.getId() == R.id.list1) {
// Handle list1 click event
} else if (adapter.getId() == R.id.list2) {
// Handle list2 click event
}
}
}