At the moment im looping through a dynamic arraylist and building a Listview with Switches and Edittexts from its data.
for (int i = 0; i < response.size(); ++i) {
...
xxx.SetId(i)
...
}
this was my working solution if a Edittext was on the first position:
if (i == 0 ) {
editText.requestFocus();
getWindow().setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
But how to set the focus on the first available Edittext? for example third position after two switches?
(the position changes dynamically based on the arraylist)
Generally you should populate and set any required state inside the Adapter that is attached to the ListView. A simple solution would be something in the lines of:
public class MyAdapter extends Adapter {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = layoutInflator.inflate(R.layout.somelayout, parent, false);
// position is zero-based so 3rd item is at position 2
if (position == 2) {
view.findViewById(R.id.edittext).requestFocus();
}
return view;
}
}
And to scroll the listview to the 3rd item you could call listView.setSelection(2).
Related
I have a configuration activity for an AppWidget. I want to let the user choose an existing string for the widget, or create one of their own by selecting the first option and editing the text within the list.
How do I change the element type of just the first list item to a different type of view that will allow users to insert custom text?
The ListAdapter interface has two methods getViewTypeCount() and getItemViewType(). So in your case, they might be implemented like this:
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
// first position has view type == 0; all others have view type == 1
return position == 0 ? 0 : 1;
}
What this does is make sure that the correct views are recycled for the correct positions. Once you have these methods, then you can do:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
// create a custom edit view and return it
} else {
// create a selection view and return it
}
}
I just want to start off by saying the list view works fine, there's no problem with this code.
All I want to know is how I can expand on it. I want to have a label (a bit of text to describe what the items in the list view represent) at the top of the list view before all of the items from the adapter appear. But obviously, because I want it inside the list view I want the label to go out of view when the user starts scrolling through the list.
How do I achieve that?
ListView listView = (ListView) findViewById(R.id.list_task_summary);
TasksSummaryListViewHelper adapter = new TasksSummaryListViewHelper(this, getTasks());
listView.setAdapter(adapter);
listView.setEmptyView(findViewById(R.id.text_empty_list));
And my template:
<ListView
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:id="#+id/list_task_summary"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#android:color/transparent"
android:dividerHeight="15sp"
android:listSelector="#drawable/list_task_summary_selector_unselected">
</ListView>
In your custom List Adapter , When getView is called, create a title view for position 0 and other position you own list item layout
#Override
public View getView(int position, View contentView , ViewGroup parent){
View row = null;
if(position == 0) {
// inflate any custom layout or just a textView
TextView titleView = new TextView();
titleView.setText("TITLE");
row = titleView;
}
else {
row = mContext.getLayoutInflater().inflate(R.layout.list_item, null);
}
return row;
}
And ,You will see the recyle issue with ListView since it uses the same child view for other items,
So to that you need to Override the getViewTypeCount and return the view type count as 2
#Override
public int getViewTypeCount() {
return 2;
}
Also, Override getItemViewType and return a unique id for position 0 and other views same id.
#Override
public int getItemViewType(int position){
// return a unique number
if(position == 0){
return 0;
}
else {
return 1;
}
}
You can do as Libin suggests, but if it's one static view that needs to scroll with the rest of the list, I think it's better to use listView.addHeaderView() instead. This way you don't need to make any changes to your adapter at all. Note that the position reported in any OnListItemClickListeners will be offset by the number of header views.
I have a ListView that's being populated by an ArrayAdapter:
someListView.setAdapter(adapter);
Each element in the adapter is inflated using the same layout.xml. Now I want to add an element of a different type (inflated using a different layout file) to the beginning of the ListView.
What I want to achieve is, to have a special element on top of all other elements in the list view, but also scrolls with the list (exits the screen from top if the user scrolls down).
I've tried to add the new element to the array but it's a different type so that won't work.
I've tried to insert a dummy element to the array at position 0, and modify the adapter's getView() so that if (position == 0) return myUniqueView, but that screwed up the entire list view somehow: items not showing, stuff jumping all over the place, huge gaps between elements, etc.
I start to think the best practice of achieving what I want, is not through editing the array adapter. But I don't know how to do it properly.
You don't need anything special to do what you ask. Android already provides that behavior built in to every ListView. Just call:
mListView.addHeaderView(viewToAdd);
That's it.
ListView Headers API
Tutorial
Do't know exactly but it might usefull
https://github.com/chrisjenx/ParallaxScrollView
In your adapter add a check on the position
private static final int LAYOUT_CONFIG_HEADER = 0;
private static final int LAYOUT_CONFIG_ITEMS = 1;
int layoutType;
#Override
public int getItemViewType(int position) {
if (position== 0){
layoutType = LAYOUT_CONFIG_HEADER;
} else {
layoutType = LAYOUT_CONFIG_ITEMS;
}
return layoutType;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
LayoutInflater inflater = null;
int layoutType = getItemViewType(position);
if (row == null) {
if (layoutType == LAYOUT_CONFIG_HEADER) {
//inflate layout header
}
} else {
//inflate layout of others rows
}
}
i want to change color of listview (simple_list_item_2 adapter) children at specific positions programmatically. (here for example all items with a = lv.getCount();)
ListView lv = getListView();
int a = lv.getCount();
for (int i = 0; i < a; i++) {
((TextView) lv.getChildAt(i).findViewById(android.R.id.text1)).setTextColor(Color
.parseColor("#EEC900"));
}
getChildAt(); doesnt always work for me. in case of the list-item being out of sceen, getChild doesnt return a view or something..
isnt there a better solution instead if getChildAt?
You will have to do this in your Adapter class. Android caches and re-cycles the views in a listview to conserve memory. So there are are no views that you can't see to change the color of.
So for example if you had an arrayAdapter, you would override the getView function and run your check there:
#Override
public View getView(int position, View view, ViewGroup parent) {
// use "position" to determine which item you have.
// Then set the properties of "view" which is your list row.
}
An activity has a Button and a ListView.
Initially, only the Button is visible. When the button is pressed, the ListView is displayed.
When displayed, is it possible for me to show one particular item as selected/focussed?
A use case could be that suppose it is a list of language settings and when the list opens, the currently selected language must be shown as highlighted.
If I know the index of the item, how to set it as focused on display?
I post my solution, because google still doesn't know the answer.
getListView().setItemChecked(selectedGroupIndex, true);
In short, ListView::setSelection(int position) is what you need. However, depending on whether the device is in touch mode or not, it may or may not have visual effect (background highlighting). For more details, refer to Android ListView Selection Problem
If you use an Adapter for your ListView add this code to your adapter:
public class MyAdapter extends ArrayAdapter<MyClass> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflator = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflator.inflate(R.layout.my_adapter, null);
} else {
rowView = (View) convertView;
}
//...
// set selected item
LinearLayout ActiveItem = (LinearLayout) rowView;
if (position == selectedItem){
ActiveItem.setBackgroundResource(R.drawable.background_dark_blue);
// for focus on it
int top = (ActiveItem == null) ? 0 : ActiveItem.getTop();
((ListView) parent).setSelectionFromTop(position, top);
}
else{
ActiveItem.setBackgroundResource(R.drawable.border02);
}
}
private int selectedItem;
public void setSelectedItem(int position) {
selectedItem = position;
}
}
In your Activity:
myAdapter.setSelectedItem(1);
I am using an Adapter and didn't want to set custom background colors, but use the android:state_selected in drawable xml. SetSelection didn't work for me, but maybe that's also since I needed SetNotifyDataChanged which shows that the Selected State is not persistent.
I also found that the Selected state for an item in a ListView is not persistent, since SetNotifyDataChanged results in updating the ListView layout which clears them all. Setting the item to Selected in the Adapter's GetView is too soon too.
Eventually I set the Selected state for the view of the selected item after the layout of the listview has been changed, which is when LayoutChange event is being triggered (in Java it's probably attaching a to OnLayoutChangeListener of the ListView).
To make it really easy I store the view of the selected item as Adapter's SelectedItemView.
In the ListView's LayoutChange eventhandler I just set the adapter's SelectedItemView.Selected to true.
Here's the code from my Activity where I set the Adapter for the ListView and also subscribe to LayoutChange (or in Java attach an OnLayoutChangeListener)
ringTonesListView.Adapter = ringTonesListAdapter;
ringTonesListView.LayoutChange += (s, layoutChangeArgs) => {
//At this stage the layout has been updated and the Selected can be set to true for the view of the selected item. This will result in android:state_selected logic to be applied as desired and styling can be completely done per layout in Resources.
ringTonesListAdapter.SelectedItemView.Selected = true;
};
Here's my code for the Adapter:
public class RingTonesListAdapter : BaseAdapter<RingToneItem>
{
List<RingTone> Items { get; set; }
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
// re-use an existing view, if one is available
// otherwise create a new one
if (view == null)
{
view = Context.LayoutInflater.Inflate(Resource.Layout.AlertSoundItem, parent, false);
view.Click += SelectRingTone;
}
RingTone ringTone = this[position];
if (ringTone.Selected)
{
//==> Important
//Store this view since it's the view for the Selected Item
SelectedItemView = view;
//Setting view.Selected to true here doesn't help either, since Selected will be cleared after.
}
return view;
}
private void SelectRingTone(object sender, EventArgs args)
{
View view = (View)sender;
string title = view.FindViewById<TextView>(Resource.Id.ringToneTitle).Text;
RingToneItem ringToneItem = Items.First(rt => rt.Title == title);
if (!ringToneItem.Selected)
{
//The RingTone was not selected and is selected now
//Deselect Old and Select new
foreach (RingToneItem oldItem in Items.Where(rt => rt.Selected))
{
oldItem.Selected = false;
}
// Select New RingTone
ringToneItem.Selected = true;
//Update the ListView.
//This will result in removal of Selected state for all Items when the ListView updates it's layout
NotifyDataSetChanged();
}
//Now play the test sound
NotifierService.TestSound(Context, ringToneItem);
}
public View SelectedItemView { get; set; }
}