I have a PopupMenu that is created dynamically. I need to pass the underlying view for this menu to another method, but I cannot find any way to get a reference to the view itself, just the menu interface and its items.
Ideally, I would do something like this:
val popMenu = PopupMenu(mainActivity, view)
popMenu.inflate(menu.route_mode)
popMenu.setOnMenuItemClickListener(this#Class)
menu.show()
viewFunction(popMenu.view)
This is not happening in the activity. This is not an Options or Context menu and is not shown in the action bar.
Unfortunately there seems no such method, i.e., you can't find the anchor view from the PopupMenu itself.
I usually create a member in the Activity to remember which View was clicked. Assume it is a Button btnPopupMenu clicked to show the popup menu, something like this:
public class MyActivity : Activity {
...
private var _clickedView:View? = null
...
override onCreate() {
...
btnPopupMenu.setOnClickedListener { v ->
_clickedView = v
val popupMenu = PopupMenu(this, v)
...
}
}
...
override onOptionItemSelected(menuItem:MenuItem) {
// use _clickedView here
}
Related
I want to show a BottomSheetDiyalogFragment dynamically with passing some parameters when a onClick event.
InfoBottomSheetDialogFragment dialog = InfoBottomSheetDialogFragment.newInstance("param1", "param2");
dialog.show(getSupportFragmentManager(), "InfoBottomSheetDialogFragment");
Also, I want to set behaivor to the fragment.
BottomSheetBehavior infoBtSheetBehaivor = BottomSheetBehavior.from(findViewById(R.id.info_bottom_sheet));
infoBtSheetBehaivor.setState(BottomSheetBehavior.STATE_COLLAPSED);
When I include the fragment xml layout on main layout, how to reach it for passing parameters?
Or, when I add the fragment programatically, how to set behaivor it? Interesting situation.
You can add BottomSheetDialogFragment dynamically and set behaivor when setupDialog like this:
In your InfoBottomSheetDialogFragment class:
// Delete onCreate(Bundle savedInstanceState) method for avoiding double inflating.
#SuppressLint("RestrictedApi")
#Override
public void setupDialog(#NotNull Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.info_bottom_sheet, null);
dialog.setContentView(contentView);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
CoordinatorLayout.Behavior behavior = params.getBehavior();
if(behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
}
}
Add dialog dynamically where you want and set parameters:
InfoBottomSheetDialogFragment dialog = InfoBottomSheetDialogFragment.newInstance("param1", "param2");
dialog.show(getSupportFragmentManager(), "InfoBottomSheetDialogFragment");
This is my first time with android programming and I got stuck.
Now I'm trying to add view dynamically which contains toggle buttons, and edittext. However, whenever I select toggle button, options I created only works on last created view.
Options are simple. There are two toggle buttons and they can be clicked mutually exclusive
example
which means whenever I add new views such as B and C in above, the options are only worked on C while not in B. How can I make it to work on every view?
public void onAddField(View v){
LayoutInflater inflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView=inflater.inflate(R.layout.data_gledger_add_new,null);
tbg_add=(ToggleButton)rowView.findViewById(R.id.add_toggle_gledger);
tbc_add=(ToggleButton)rowView.findViewById(R.id.add_toggle_credit);
if(create_box<4){
csl.addView(rowView,csl.getChildCount()-1);
Log.d("create_box",String.valueOf(create_box));
create_box++;
}
else{
Log.d("create_box","full");
create_box=4;
}
tbg_add.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
if(tbg_add.isChecked()){
get_add_cla="menu1";
tbg_add.setTextColor(getResources().getColor(R.color.color_white));
tbc_add.setChecked(false);
tbc_add.setTextColor(getResources().getColor(R.color.color_black));
}
else{
get_add_cla="";
tbg_add.setTextColor(getResources().getColor(R.color.color_black));
}
}
});
//대변 선택
tbc_add.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
if(tbc_add.isChecked()){
get_add_cla="menu2";
tbc_add.setTextColor(getResources().getColor(R.color.color_white));
tbg_add.setChecked(false);
tbg_add.setTextColor(getResources().getColor(R.color.color_black));
}
else{
get_add_cla="";
tbc_add.setTextColor(getResources().getColor(R.color.color_black));
}
}
});
}
I forgot to mention that views are added by clicking button.
android:onClick="onAddField"
The problem almost certainly stems from the fact that you are re-using instance fields (tbg_add and tbc_add) as add new views dynamically.
tbg_add=(ToggleButton)rowView.findViewById(R.id.add_toggle_gledger);
tbc_add=(ToggleButton)rowView.findViewById(R.id.add_toggle_credit);
Because you are re-assigning these fields and also referencing them from the click listeners, you'll always be referencing the most recently created toggle buttons.
Change these to be local variables and everything should work fine.
ToggleButton ledger=(ToggleButton)rowView.findViewById(R.id.add_toggle_gledger);
ToggleButton credit=(ToggleButton)rowView.findViewById(R.id.add_toggle_credit);
Unrelated to your problem, but also something you should fix, is the fact that you're passing null as the second parameter to your inflate() call:
final View rowView=inflater.inflate(R.layout.data_gledger_add_new,null);
When you pass null in this manner, the system won't have any ability to correctly handle the LayoutParams (anything starting with android:layout_ in the xml file) for the newly-inflated view.
You know that you're going to wind up adding the rowView to your csl view, so you should pass that as the second parameter. Once you do that, you also have to pass false as a third parameter to make sure that the inflate() call actually returns the rowView and not its new parent (csl).
final View rowView=inflater.inflate(R.layout.data_gledger_add_new, csl, false);
I've been working on an online shop type of application, and I've hit a bump: I've been tasked to add a favorites system, but I can't figure out how to enable pressing a button that's part of the RecyclerView item to add it to favorites.
(In this case, the heart, which is supposed to turn to a full heart when clicked)
Add a boolean value for favourite in your list . Initially , keep it false .
You need to have two drawables , one for selected state and another for unselected state .
In your onBindViewHolder , set the drawable on runtime on the basis of above condition .
if(list.isfav)
{
holder.ivHeart.setImageDrawable(ContextCompat.getDrawable(context,(R.drawable.selected));
}else{
holder.ivHeart.setImageDrawable(ContextCompat.getDrawable(context,(R.drawable.unselected));
}
Put onClick on this ivHeart eg:
holder.ivHeart.setOnClickListener(v -> {
if(list.isfav) {
list[adapterPosition].isfav = false;
}else{
list[adapterPosition].isfav = true;
}
notifyItemChanged(adapterPosition);
});
Dont forget to notify the item while changing item .
In your RecyclerView adapter's onBindViewHolder() method, add click listener to your view and change the drawable programmatically.
The code will be something like this
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
holder.your_like_imageview.setOnClickListener{
holder.your_like_imageview.setImageDrawable(ContextCompat.getDrawable(context,R.drawable.something_else));
};
}
I'm assuming you're using an ImageView for the heart. What you can do is set a click listener on that ImageView and process that click.
An ideal way to do this would be to use an interface to handle click events that you pass to the Adapter.
However you could do something like this in the onBindViewHolder method:
imageView.setOnClickListener {
// depending your logic change the tint for the icon or the drawable
onClick(data[position], addToWishlist)
notifyDataSetChanged()
}
The onClick method will receive the particular item and a flag to add or remove it from
the wishlist:
fun onClick(data: Data, addToWishlist: Boolean) {
// you can perform the addition/ deletion from the wishlist here
}
I targeted the items in an action bar using ShowcaseView, but I can't target elements of a ListView! I tried that and it didn't work:
ShowcaseView sv = new ShowcaseView.Builder(this,true)
.setTarget(new ViewTarget(lv.getChildAt(1).findViewById(R.id.heart)))
// Here is where you supply the id of the action bar item you
// want to display
.setContentTitle("Heart")
.setContentText("Check the venues of your city")
.hideOnTouchOutside()
.build();
Very simple. Take the element in your ViewHolder then place the code for showing the ShowCaseView inside your bindView.
Don't forget to put different a different ID for each element in the list.
So you may try something like this.
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView button;
public ViewHolder(final View itemView) {
super(itemView);
button = (Button) itemView.findViewById(R.id.list_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new MaterialShowcaseView.Builder(getActivity())
.setTarget(verifyButton)
.setDismissText("GOT IT")
.setContentText("Your text goes here")
.setDelay(100) // optional but starting animations immediately in onCreate can make them choppy
.singleUse(id + " define an unique id for each item of the list") // provide a unique ID used to ensure it is only shown once
.show();
}
});
}
}
}
To get more information you can check the library here.
I'm trying to set a header and footer in my list view that are clickable buttons. The problem is that the OnClickListener isn't responding to anything and I can't figure out what I'm doing wrong.
$ View header = getLayoutInflater().inflate(R.layout.header_layout, null, true);
getListView().addHeaderView(header);
myAdapter = new myAdapter(this);
header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do what I want when i click it
}
});
Update
The best solution I ultimately came up with was adding a separate button to the header layout, and then doing it like this:
View header = getLayoutInflater().inflate(R.layout.header_layout, null);
Button headerButton = (Button)header.findViewById(R.id.header_button);
getListView().addHeaderView(header);
headerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// My Click Stuff
}
});
You need to handle the click in the ListView's onItemClick. Simply check if that's the first or last item in the adapter and handle the clicks that way. You need to treat it as an item in the ListView.
I see a few issues:
when inflating the header, use getListView() as the second parameter (root, where you have null now)l
should the header be a View or a ViewGroup? I've ended up using ViewGroup in these situations.
finally -- perhaps you should be setting the click listener on the button in the header instead of the header itself?
There is a way more easier solution:
Just set a "OnClickListener" to the applied View:
View view = inflater.inflate(R.layout.xxx, null);
view.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
//do something
}
});
Very easy thing which solved it!
Example with a footer:
mYourListView.addFooterView(footer, null, true);
Then in the OnItemClickListener you can check:
#Override
public void onItemClick(AdapterView<?> parent,
View view, final int position, final long id) {
if (id != -1) {
// do whatever you do with list items
} else {
// do what you need after the footer been clicked
}
(If you need to handle and the header and the footer click, check position - 0 for the header and [adapter.getCount() - 1] for the footer)
This approach will provide the same visual effect while footer click as if the list item been clicked. (But if you do not need that effect just add OnClickListener to the footer and it will intercept all footer clicks)
i think the listview and buttons are fighting for focus and your listview is winning.
you'll have to use a onTouchListener for the buttons.
There is one more alternative and its to set the following on the footer. There is another method overload created but it did not come up in the docs, i had to check online documentation:
mylistView.addFooterView(footerView, null, false);
where false tells the footer its not selectable. I tested this myself and the buttons inside the footer respond to touches now. I hope this an acceptable answer.
What worked for me:
When inflating the header view, before adding it to the listview, I then used that view to get the subview and add a click listener on it
myHeaderView.findViewById(R.id.myButton).setOnClickListener(new OnClickListener() { ... } );
also, when I added it to the listView, I used the overloaded constructor with the third variable set to true
mListView.addHeaderView(myHeaderView, null, true);