The code below works. But I know it is not the right way of doing things and I would like to know what is the right way to do this. I have a Keyboard service that that displays GIF images in a ListView. But the ListView needs an activity to show it. How do I get an activity in my ListView? (I have already tried casting the service as an activity. I get an invalid cast exception)
public override View OnCreateInputView()
{
View imageKeyboardView = (View)LayoutInflater.Inflate(Resource.Layout.ImageKeyboard, null);
listView = imageKeyboardView.FindViewById<ListView>(Resource.Id.List); // get reference to the ListView in the layout
Activity act = MainActivity.Instance;
// populate the listview with data
listView.Adapter = new ImageKeyboardAdapter(act, listOfIconUris);
listView.ItemClick += OnListItemClick; // to be defined
return imageKeyboardView;
}
You could try using CurrentActivityPlugin to get your Application’s current Activity that is being displayed.
Related
I have an Activity, which has a RecyclerView and save Button. Each item (football match) of the RecyclerView contains some text (name of teams) and EditText, where user enters data (actually bet the match). My goal is to save those scores to the list in the Activity, when user clicked on save Button.
I implemented this method in Activity, which actually get particular item from LinearLayoutManager and then get data from EditText, but the findViewByPosition() method (or getChildAt() there are different way to do this) sometimes returns null.
I saw another answers on similar question, but they didn't help me. Maybe my strategy is wrong, because I made whole my logic in Activity (better to do this in Adapter?) and I get though all of my items in RecyclerView even if only in one user entered the score.
private List<Bet> getUserBets() {
View betView;
Bet betItem;
EditText userBet1;
EditText userBet2;
int numberOfMatches = rvBetsAdapter.getItemCount();
List<Bet> bets = new ArrayList<>();
for (int i = 0; i < numberOfMatches; i++)
{
betItem = rvBetsAdapter.getItem(i);
betView = linearLayoutManager.findViewByPosition(i);
userScore1 = (EditText) betView.findViewById(R.id.result1); // <- NPE appears
userScore2 = (EditText) betView.findViewById(R.id.result2);
//here i checked whether the editText is empty and other stuff
bets.add(betItem);
}
return bets;
}
How do I fix it? I suppose I should do something in onBindViewHolder method in my adapter, but what exactly?
I would really appreciate any help.
You should add to your Bet model variable which holds EditText value for example editTextValue.
And access it using list in adapter list like this end use EditText value from there. rvBetsAdapter.getItem(i).editTextValue
editTextValue can be set using TextWatcher.afterTextChanged() callback
You can only find or get views that are visible on the screen.
before using findViewByPosition(2)
go to position 2 by recyclerView.scrollToPosition(2);
if you want to change value of this views, The best way is get your item in list
yourModel item = (yourModel) itemList.Get(2)
item.Name = "Edited";
yourAdapter.notifyItemChanged(2);
I'm working on a fragment that contains a listview (this fragment is PlaceHolderFragment generated when create activity). I extends ArrayAdapter to make my custom adapter and fill my listview with this adapter.
One important thing is in one row of listview, there are 2 buttons: first is the enable/disable button to change status of an user (when user's status is active then it's disable, otherwise enable), second is the delete button (to delete user). So I have to implement OnClickListener for this 2 buttons in method getView() of adapter
When click either buttons, it will send request to server and manipulate database (change user's status or delete user from database). The thing is when I click enable button (for example), it is success and user's status in database is changed, or when I click delete button, user will be delete from database successfully
BUT after I click that button, it's state does not changed (I mean if user is enabled, now the button must change to disable, or if user is deleted, that row must be remove from screen). I have to reload this fragment by hand (switch to other fragment and then come back)
The question is how can I reload activity (I already implement onResume to load all data to adapter, so if I can make this method onResume of fragment run, it will work as my expectation), or at least how can I reload the listview to update new data?
Note: notifyDataSetChanged() DOES NOT work because the data in adapter actually doesn't change yet, only data on server are changed
Note 2: if you need me to post my code, please comment and I will edit my post, because I think my code is long
Thank you and best regards!
EDIT 1
I've posted my solution in the answer below, it fix the problem but I have to say that this is a very very BAD practice in android. For example, when you want to delete an item with this approach, you may want to put a AlertDialog for user to confirm, but AlertDialog can only show in Activity (or Fragment), it can't be show from Adapter. So instead, you should use some different methods such as ContextMenu or CustomDialog.
After couple of weeks searching google and try different methods, I finally found a way to archive what I want, and it's very simple. I post my answer here for anyone facing this problem like me in the future
public class CustomAdapter extends ArrayAdapter<YourClass> {
private List<YourClass> items;
private CustomAdapter adapter;
private Context context;
private Button button;
private YourClass item;
public CustomAdapter(Context context, List<YourClass> items) {
super(context, R.layout.custom_list_item, items);
this.items = items;
this.context = context;
this.adapter = this; //This is an important line, you need this line to keep track the adapter variable
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.custom_list_item, null);
}
item = items.get(position);
button = (Button) v.findViewById(R.id.button); //Find the button
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//Do something inside here like update, remove your item...
//But the important is
items.remove(item); //Actually change your list of items here
adapter.notifyDataSetChanged(); //notify for change
}
});
}
return v;
}
That's it, all you need to implement when you need the listview to reload in case you need to implement OnClick inside the adapter. Hope you guy find it easier than me when you face this problem
What I understand from your question that you want to refresh the list data when click on one of the button as you need.
Now You should call notifydataset change rather reloading the activity again.
For this you need to change the array that yu are using for the adapter(Don't change the array object just the Item of the array)
like arraylst.get(index).activ=true etc etc and then call notifiydataset change.
I created an expandable listview based on this link. Its just working fine. Now what i want is
1) How to make a childview to link another sub-child view
2) The sub- child view should be open as a new list view on the window(Right side of the view) is my expected layout. I googled but couldn't find how to achieve this. Please help me in achieving this. Thanks in advance.
You'll need to specify and handle onClick event of ListView row items.
Then you'll open a new Activity, based on the item clicked.
Parameters for new activity are supplied through intent extras, the new activity can use these values to get data from cloud or process the values to show certain results.
I've used CustomAdapter class several times to handle this scenario.
class Ocl implements OnClickListener{
#Override
public void onClick(View v) {
Intent intDetail = new Intent(getActivity(), PartDetail.class);
intDetail.putExtra(_ID, mParts[position].getSPr());
intDetail.putExtra(_LOT, mParts[position].getLotID());
intDetail.putExtra(_QTY, mParts[position].getQty());
intDetail.putExtra(_UID, mParts[position].getPartID());
startActivity(intDetail);
}
}
So, do you want your first child to expand into another ListView? Or maybe just open another Activity/Fragment that contains the matching ListView?
In case you want to the the first, you could design a CustomLayout for the Childview, which on OnClick expands, and changes its content to a specific ListView.
Otherwise you would just open up another ListView with data depending on Which Child in First List was Clicked.
Well, i am using some Like that to enlarge ChildViews on Click to show me detailed information.
Im using a Class to wrap my Data named Row. These Rows indicate if they are clickable and if so, the ListView will allow clicks on the rows. A Click will then be handled by the Class itself, making the displayed Text longer(more Detailed). And in order to relayout the items, you need to call notifyDataSetChanged.
#Override
public void onClick(Context context, MyExpandableListAdapter mela) {
this.setBig(!isBig());
mela.notifyDataSetChanged();
}
So, i would handle the row state (expanded/normal) in the getView Method of parents Adapter, to decide which childLayout i inflate.
would looke something like this
public View getView (args...) {
Object data = getItem(position);
if (data.isExpanded()) {
//inflate ListView Layout, create Addapter fill it....
} else {
//show some title or whatever to identify row.
}
}
I implemented a View stack system for my Android application, which, upon pushing a new View removes the current view in the target layout, stores it in the stack and then adds the new View to the layout.
It works flawlessly until I try storing and then restoring a View containing a ListView. When doing so, the ListView receives no itemClick events, although it does scroll.
The code for the stack system is as follows:
Stack<View> viewStack;
public View pushView(View v) {
// 1. Get reference to main content panel
LinearLayout content = (LinearLayout) findViewById(R.id.contentPanel);
View last = content.getChildAt(0);
// Pushing old to stack
viewStack.push(last);
// 2. Clear it
content.removeAllViews();
// 3. Add new View
content.addView(v);
return last;
}
public View popView() {
if (!viewStack.isEmpty()) {
// 1. Get reference to main content panel
LinearLayout content = (LinearLayout) findViewById(R.id.contentPanel);
View last = content.getChildAt(0);
// 2. Clear it
content.removeAllViews();
// 3. Add last View
content.addView(viewStack.pop());
// Pushing old to stack
return last;
} else {
return null;
}
}
Curiously, the other items in the View that contains the ListView (CheckBoxes and a Button) DO receive clickEvents.
I suspect:
1. The ListView has lost focus so it won't receive those events, or
2. The ListView has been detached of the onItemClickListener
Thanks in advance!
If you have set "clickable" as "true" in you layout in xml file then remove it from every where. then you can try...
If you are declaring anywhere then only. If you are declaring "view_name.setClickable(true)" then remove this line. One more thing if you are using ontouchlistener then always return false. Actually i have faced similar problem in which I was using listview and imageview in listview row. My imageview was receiving click event but listview was not receiving onitemclick event because i had set imageview as clickable in my layout.
I want to show an empty list view, which is then populated by user input. I have the UI flow working, and I populate a list of my custom objects after the user enters some information via a view which is invoked through setContentView (i.e. no a new Activity).
I take the input and add it to a list, which I want to be summarised on the ListView. However, whenever I add to the list and/or the ArrayAdapter and call adapter.notifyDataSetChanged() it does not do what I want. The ListView is still empty. Argh! It's driving me insane!
#Override
public void onCreate(Bundle blah) {
ListView listView = (ListView) findViewById(R.id.results_list);
listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, list));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnu_add:
final Activity act = this;
setContentView(R.layout.record_details);// the sub-view that takes the user input
// the button on the form to 'add' details:-
((Button) findViewById(R.id.recored_details_add_btn))
.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
// get input from widgets
list.add(someObject);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
setContentView(R.layout.list_view);
}
}
);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
break;
}
return true;
}
Please, save me from my misery and inform me of my stupidty?
Thanks in advance.
public void onClick(View v) {
// get input from widgets
list.add(someObject);
((ArrayAdapter<Object>) listView.getAdapter()).notifyDataSetChanged();
setContentView(R.layout.list_view);
Is it possible that this setContentView in the onClick handler is creating a new instance of the list view widget (with no adapter) or reinitializing the list view (clearing the adapter)?
Try putting something in the list initially in onCreate and then see if it disappears when you hit the button.
I haven't seen any code (although I'm a relative newbie) that switches views within the activity's lifetime to bring up essentially bring up different pages - most use a separate activity.
Edit:
OP asks:
Thanks...So how can I get what I want? The list I'm backing the adapter with is static; should I just use activities instead and rely on onCreate loading from the static field?
Some options:
Use separate activities
Re-associate the adapter (call setAdapter again) - probably a bad idea
Declare both layouts in the same file. You'll hide one and unhide the other to switch between views rather can calling setContentView. This is similar to how ListView layout works (one for when the list is empty and one for when it is not). I think I've seen an example of this somewhere on the net, but I don't have a reference right now.
You could relaunch the same activity by using Intent.FLAG_ACTIVITY_SINGLE_TOP flag while creating the intent and override the onNewIntent() method.
Inside the onNewIntent() you create the adapter with updated data and call setAdapter.
I think this will give you the intended behaviour.