I want to make an application that show lyric of sound with music,
I put lyrics in a custom made listview with layout below ( layout for row's ), and time of that lyric in text separated with comma,
then, I want to scroll with media.
This is my custom layout for rows:
<TextView
android:id="#+id/custom_text_arabic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center"
android:lineSpacingExtra="15dp"
android:textSize="20sp" />
<TextView
android:id="#+id/custom_text_persian"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="10dp"
android:textColor="#999999"
android:textSize="12sp" />
</LinearLayout>
and I have an adapter for this custom row layout in list view,
I have a music file that plays with MediaPlayer and I get current position of sound and check that in an array of time to find the position of row in list view, then I scroll to that row in a listview, along side this things, I want that row background change to black!
So, I get that row with this code and change it!
// cAdapter is the name of my BaseAdapter and whereIsMe is current child of listview
// that i want to manipulate it
View mVi = cAdapter.getView(whereIsMe-1, null, lv);
TextView persian = (TextView) mVi.findViewById(R.id.custom_text_persian);
// this toast works great!
Toast.makeText(getApplicationContext(),persian.getText(), Toast.LENGTH_LONG).show();
// this part of code is not working!
persian.setBackgroundColor( Color.BLACK );
the problem is:
I can Toast Text in a TextView perfectly! But I can't change that TextView Background or any other manipulation! why and how can I fix that?
Calling getView doesn't return the actual child of the ListView. There are two options, you can call getChild for the ListViewand update the background color or call notifyDataSetChanged and set the background color in your adapter getView method.
The getView method of the adapter is not meant to be used as you are using it.
Read some tutorials on creating a custom adapter for a listView. Then you can do whatever you want.
Here is a good read on custom adapters;
http://www.vogella.com/tutorials/AndroidListView/article.html
For getting the view you want from outside the adapter use something like this:
View view;
int nFirstPos = lv_data.getFirstVisiblePosition();
int nWantedPos = invalidaEste - nFirstPos;
if ((nWantedPos >= 0) && (nWantedPos <= lv_data.getChildCount())
{
view = lv_data.getChildAt(nWantedPos);
if (view == null)
return;
// else we have the view we want
}
Sometimes listView.getChildAt(int index) returns NULL (Android)
This happens because getView is called internally to create a view. by what you are doing you are actually creating a new view which is not added to any screen/layout so any changes you do wont be reflected on the UI
Related
I want to create an expandable list view except in this case, when a list item is clicked, i do not want to just want to show another a list of strings but rather I want it to show a layout with text fields and drop downs etc.
So far, I have parentlayout with textview to show the titles, childlayout with fields in it. Just not sure how to show the child layout on list item click. Any help is greatly appreciated!
HashMap<String, List<String>> would be used if I wanted to show a list of strings so in my case, what do I use? HashMap<String, ?> what goes here?
Looks like you are looking for something like BaseExpandableListAdapter. You can customize both the group and child views with whatever you want.You just have to implement some of the methods.For example getGroupView and getChildView will return any View. You can inflate the view in this method and set it up too.
Here are two articles for reference:
http://www.javacodegeeks.com/2013/06/android-expandablelistview-with-custom-adapter-baseexpandablelistadapter.html
http://theopentutorials.com/tutorials/android/listview/android-expandable-list-view-example/
What I ended up doing, which was much easier and more effective is I created a linear layout with all the fields I needed and added some textviews to serve as section titles. Then I declared it like so
in onCreate
textview= (LinearLayout)findViewById(R.id.textviewid);
textview.setVisibility(View.GONE);
Then wrote a method called toggle
public void toggle_basicInfo(View v){
if(textview.isShown()){
textview.setVisibility(View.GONE);
}
else {
textview.setVisibility(View.VISIBLE);
}
}
my xml looked like
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Basic Info"
android:clickable="true"
android:onClick="toggle_basicInfo"
android:textSize="20sp"
android:paddingTop="8dp"
android:id="#+id/text"
android:layout_above="#+id/linearLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="#ff3a65ff" />
when I click my textview, it will hide/show whatever you define to hide. for example you can hide a LinearLayout etc. Also by doing it this way, state entries for text fields are maintained when hidden and shown.
I have a messaging application. I can get messages and list from mysql database via json. When i get messages (for example last 10 messages and newer is at the bottom) first record is shown at the top, so user have to scroll down to see last message. I want to focus to last message and when user scrolls to top, I want to put there a Load Previous Messages button. I found Load More buttoni but its at the bottom of page. How can I do that?
My codes are these:
// Hashmap for ListView
categoryList = new ArrayList<HashMap<String, String>>();
// get listview
ListView lv = getListView();
Button btnLoadMore = new Button(this);
btnLoadMore.setText("Load older messages");
FrameLayout footerLayout = (FrameLayout) getLayoutInflater().inflate(R.layout.listfooter,null);
lv.addFooterView(btnLoadMore);
As I said in comments, simply change addFooterView() to addHeaderView() method which give you the Load More at the top of the list. This method use three parameters (at least one: View from reference) which are:
View v: the Load More view to add at the top
Object data: data associated to the view
boolean isSelectable: value to make the view selectable or not
Using these three params instead of only the view may allow you to prevent the color state on it by using android:listSelector attribute. Indeed, sometimes you want to prevent a background state on a header/footer view. That being says, the method might be:
lv.addHeaderView(headerLayout, null, false); // this isn't clickable now
Note: now, you can call the view variable headerLayout instead of footerLayout ;)
As I understand your requirements, HeaderView should have the Load More Button into it, to avoid to create it dynamically, as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Load More"
android:onClick="loadMoreDatas" />
</LinearLayout>
Now, you have the right Button at the top of your list and you can add a method to handle the click event into the Activity (refer to android:onClick attribute) as:
public void loadMoreDatas(View v) {
// load more messages
}
Finally, to focus to a specific item, in your case the last item in the list (at the bottom), you should use setSelection(int position) which go to the index selected in its parameter. Then, after setting the Adapter, call this on the ListView as:
// set the adapter
setListAdapter(adapter);
// go to selection (last item)
lv.setSelection(adapter.getCount() - 1);
The getCount() method use (normally) your ArrayList size. Then, you have to prevent an IndexOutBoundsException because your array begins with position 0 and not 1. So, the last position is "All Items less First Position (0)".
However, the perfect method to begin at the bottom of the list is setStackFromBottom():
When stack from bottom is set to true, the list fills its content starting from the bottom of the view.
Then, it might be better to have:
// start from bottom
lv.setStackFromBottom(true);
This should do the trick and I hope this will be usefull.
I am working on a ListView and I have used setBackgroundColor inside onItemLongClickListener on the selected item. My problem is that when I am doing this and scrolling, it is setting color of some invisible child of ListView too. How can it be solved.
Try putting the following attributes in your xml:
`
<ListView
android:dividerHeight="1dp"
android:scrollingCache="false" >
`
this is caused since a listview uses old views in order to avoid re-creation of views when you scroll.
in fact , this is common to all of the adapterView classes .
in order to handle this , store the status of the position of the view (using an arrayList or whatever collection you wish) and on the getView , if the position is set in the list to be of this background , use this background , otherwise use the default background.
for more information about listview , either read the API , or (and i highly recommend it) watch the video "the world of listView" .
In your adapter class:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = inflater.inflate(...);
}
convertView.setBackgroundColor(defaultcolor);
...
}
This however will overwrite the background you set in the onlongclicklistener when that view would be redrawn. So you might want to keep a list of the positions of the clicked items so you can set these in the getView method.
I have a row for a ListView defined as :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/menutext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="24sp"
android:layout_alignParentLeft="true"/>
<ImageView
android:id="#+id/icon"
android:layout_width="40dip"
android:layout_height="40dip"
android:src="#drawable/lock"
android:layout_gravity="right"
android:layout_alignParentRight="true"/>
</LinearLayout>
My adapter for the ListView is set in onCreate()
listView.setAdapter(new ArrayAdapter<String>(this, R.layout.send_menu_row, R.id.menutext, items));
I have 5 rows with a text and image on each row. In onResume(), I want to make the first row's ImageView invisible.
#Override
protected void onResume()
{
super.onResume();
LinearLayout linLayout = (LinearLayout) listView.getAdapter().getView(0, null, null);
ImageView v = (ImageView) linLayout.getChildAt(1);
v.setVisibility(View.INVISIBLE);
}
But it doesn't change the visibility. Can someone help me on this?
Probably what is happening is that you are not doing that in the right method.
Try to switch the device orientation from horizontal to vertical (or vice-versa). This should trigger onResume method to be invoked and it could work.
Anyway, hiding an image shouldn't be done that way. Perhaps you should use an empty image or override the getView method (in the adapter).
UPDATE - why do I say you shoudn't use this method to do that
The thing is adapter.getView is used to get a view that will be drawn. The OS calls this method when he needs to draw that item on the screen.
This method could be overriden by the developer to draw custom/complex views but it should be used (as in, invoked) exclusively by the system.
For example, when we are talking about long lists, if you scroll, you'll have the getView method invoked and it will receive a view to be reused (which is a lot more efficient). This means that if you hard-core that the first view will be invisible, when you scroll and the first view is reused to display the 20th item (for example), now the 20th item would be invisible because probably you would just update the label and image source.
Note:
When I say first view, I'm referring to the view where the first item is initially drawn. Later, the view that was used to accommodate the first item is going to be reused to accommodate another item.
What is happening:
I think I got it now. What I believe to be happening is the following:
When the activity is initially drawn, you'll have the getView method invoked 5 times (one for each item that you are displaying). Each time the OS collects the view returned and adds it to the listview.
Latter, you'll call getView by yourself. As you pass no view to be reused, the method will create another view and return it. What is different this time? You are not adding this view to the listview. (Also, this isn't what you what to do.)
what you wanted to do is get the view that was used to draw the first item. But in this case you are just getting another view that could be used to draw the first item.
The solution is overriding getView or using a transparent image (easier).
Here's a link for the first result on google:
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
How about override getView and then do setVisibility when you return the first row in getView()?
It's not a great idea to be modifying rows outside of the list adapter. Since everytime the user scrolls you will lose the changes.
A workaround maybe ?
Try making a transparent image (png) and put that in as first item :-)
How do you get the first list item in a listView? I want to get at a TextView in the first list item.
I am currently doing this:
View listItem=(View)myList.getChildAt(0);
TextView txtDep=(TextView)listItem.findViewById(R.id.txtDepart);
txtDep.setText("Hello!");
But this is not only changing the text in the first item but in every 8th, 16th and so on items. I would like to change the text in the first(top) item only.
Thank you.
Views are recycled so your TextView will be used for many different items in the list. If you want to change what a specific item displays then you need to change the data that is behind your ListItem and is being served up by the ListAdapter (in the getView() method). So whenever the ListView shows the item in the list, the adapter will show the correct data in the TextView.
And when you change data in your list or whatever, you will need to call notifyDataSetChanged() on your adapter.
If you want to get the specific item in the list and want to change its color you can get this through getView method in your Adapter class.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
{
LayoutInflater inflater = (LayoutInflater)context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.crewlist_row, null);
}
TextView firstname = (TextView)convertView.findViewById(R.id.firstname);
firstname.setText(userArray.get(position).getFirstName());
return convertView;
}
Shouldn't you use getItem(0) ?
http://developer.android.com/reference/android/widget/Adapter.html#getItem%28int%29
What you want to do is change the data in the ListAdapter and then call the notifyDataSetChanged() method to get the list to re-render. See the discussion here, includes some sample code:
ListView adapter data change without ListView being notified
Same symptom but different cause for me. I changed my fragment layout to a controlled height instead of match_parent and that solves my issue.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
to
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal" >