My app is designed as follows:
Main Activity uses action bars
First tab is a fragment that is split into 3 sections
| Linear Layout containing List view | |Linear Layout containing List View | | Linear Layout containing media controls and image view|
I have two AsyncTasks within this activity, one that fills the centre list view, the other that starts with the media controls to fill the image view (album art).
Both of these are working well. The List view AsyncTask throws a progress dialog spinning wheel. This is coming up in the centre of the screen. I understand that I can put this spinner into the top right of the application. But can i place it either in the top right of the list views linear layout, or centred at the back of the linear layout? That way it would be unobtrusive yet obvious what the progress bar applied to?
Thanks in advance
I understand that I can put this spinner into the top right of the
application. But can i place it either in the top right of the list
views linear layout, or centred at the back of the linear layout?
If you can calculate the position of the view, you would probably be able to position the ProgressDialog where you want(for example see this question I answered Change position of progressbar in code). Also, keep in mind, that this could be very counter intuitive for the user who would see the screen for the dialog and the dialog placed at some weird position(he may not make the correlation between the position of the ProgressDialog and the view for which the data is loaded).
Another option could be to modify the current layout for the ListView part to add on top an initial gone FrameLayout(which will cover the entire ListView) with a background that simulates the background for a screen with a Dialog(this FrameLayout will contain a ProgressBar placed where you want). This FrameLayout would be made visible when the AsyncTask kicks in(it may be wise to block the touch events for the underlining ListView). This way the user can still do stuff in your app and it has a clear indication for the View that is loading its data. Of course this will work well if it's possible for the user to work with the other data independently from the loading ListView.
The answer from Luksprog is so good that I thought I should list the code here: Absolutely perfect
main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/first_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/anchor" >
</ListView>
<View
android:id="#id/anchor"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_centerVertical="true"
android:background="#99cc00" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/anchor" >
<ListView
android:id="#+id/second_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="#+id/overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#33c1c1c1"
android:visibility="gone" >
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|top"
android:indeterminate="true" />
</FrameLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends Activity {
private String[] mItems = { "Item no.1", "Item no.2", "Item no.3",
"Item no.4", "Item no.5", "Item no.6", "Item no.7", "Item no.8",
"Item no.9", "Item no.10", "Item no.11", };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
// setup the two ListViews
ListView firstList = (ListView) findViewById(R.id.first_list);
firstList.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mItems));
firstList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// just as an example, one you click an item in the first
// ListView
// a custom AsyncTask will kick in to load data in to the second
// ListView
new MyTask(MainActivity.this).execute((Void) null);
}
});
ListView secondList = (ListView) findViewById(R.id.second_list);
secondList.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mItems));
secondList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// just to test that you can't click the ListView if the data is
// loading
Toast.makeText(getApplicationContext(), "click",
Toast.LENGTH_SHORT).show();
}
});
}
private class MyTask extends AsyncTask<Void, Void, Void> {
private MainActivity mActivity;
private FrameLayout mFrameOverlay;
public MyTask(MainActivity activity) {
mActivity = activity;
}
#Override
protected void onPreExecute() {
// the AsyncTask it's about to start so show the overlay
mFrameOverlay = (FrameLayout) mActivity.findViewById(R.id.overlay);
// set a touch listener and consume the event so the ListView
// doesn't get clicked
mFrameOverlay.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
mFrameOverlay.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
// do heavy work
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
//remove the overlay
mFrameOverlay.setVisibility(View.GONE);
// setup the ListView with the new obtained data
String[] obtainedData = { "D1", "D2", "D3" };
ListView theList = (ListView) mActivity
.findViewById(R.id.second_list);
theList.setAdapter(new ArrayAdapter<String>(mActivity,
android.R.layout.simple_list_item_1, obtainedData));
}
}
}
Luksprog, hope you don't mind me posting your code, just didn't want it to vanish from git and this answer be lost to others.
Related
I have a custom layout for my list view rows:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/listSelector"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/checkboxSelection1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dip">
<CheckBox android:id="#+id/checkbox1" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/checkbox1"
android:orientation="vertical">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
I've also got an adapter to get the appropriate data to display; which it does. From the UI perspective, it looks like I want it to.
However, when I click a checkbox - nothing happens. I want to store a list of the items I've selected in the backend (in the activity class ideally).
In my onCreate in the activity class, I've got this code:
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// Click event for single list row
listView.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
int i = 1;
}
});
I've got the int 1 = 1; line there just so I could add a breakpoint to see if it gets hit. It doesn't. I'm sure I'm doing something wrong, like it's hooked up to the list view row instead of the checkbox or something - but I'm not sure how I can hook the event up to the checkbox.
If anyone could point me in the right direction I would appreciate it.
Thanks
Edit: JUST TO CLARIFY
I have this in the adapter:
taskChecked.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton arg0, boolean arg1)
{
// TODO Auto-generated method stub
int i = 1;
}
});
And that breakpoint does get hit. So I'm just trying to find out how I get have an event get raised in the activity, instead of just the adapter, when a checkbox is selected or unselected.
Don't do it!!! I almost went mad trying to get widgets in a ListView to respond to clicks. Do not put Button, ImageButton, or CheckBox widgets in a ListView. TextViews and ImageViews are the way to go. Trying to react to that click on that CheckBox to find what ListView item it is in and then send something to the Activity could be very harmful to your health. I tried.
TextView + ImageView that can vary between an icon showing a checkmark and one without - simulate a CheckBox;
ImageView by itself can simulate a Button.
The ImageView needs to be set to focus=false.
First, create a new class that has the fields you want to display for each item in the ListView. I made one with the text to display and a boolean that indicates whether it is checked or not. Use this class for your ArrayList and ArrayAdapter.
Then you add the setOnItemClickListener() for the ListView, then use the position to find the item view, and then get the item of your new class and toggle its boolean.
In the MyArrayAdapter.getView method, getItem(position) returns the instance of the new class for that item. Use the boolean to determine what icon to use for the ImageView.
When you need to know what is and isn't "checked" in the ListView, you just go through the ArrayList and check the boolean for each item.
I figured it out.
In the adapter I added this:
With _activity being the activity passed into the constructor from the calling activity. myObj is declared as a final earlier up in the code, based on the position in getView and the data passed in when the adapter was constructed.
taskChecked.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton button, boolean checked)
{
// Cast it so we can access the public functions
MyActivity myActivity = (MyActivity) _activity;
if (checked) // true if the checkbox is checked, false if unchecked
{
myActivity.checkboxSelected(myObj);
}
}
});
And in the activity I added this:
public void checkboxSelected(MyObj myObj)
{
// Do stuff with myObj here
}
Hopefully this helps someone.
I have this:
Where Red square is the activity containing several fragments, almost all of them are lists, all of them with different items but built by my custom ListAdapter class.
Orange square is one of those fragments, actually it's a right drawer. This fragment extends from ListFragment, and inflates a simple xml without Items.
Inside of the fragment's onActivityCreated I instantiate a custom ListAdapter which I fill with the items you see in the screenshot.
I have several xml depending on the type of Item I want, here you can see 3 of them:
Button Title (The green square)
Checkable item (The ones which can have the checked icon at right)
Regular Title (The one that says "Día y hora del viaje")
Button title (Green square) xml is a simple linear layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/menu_row_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/row_button"
android:layout_width="45dp"
android:layout_height="45dp"
android:padding="10dp" />
<TextView
android:id="#+id/row_title"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:minLines="1"
android:padding="10dp"
android:textAppearance="#android:style/TextAppearance.Medium"
android:textStyle="bold" />
</LinearLayout>
What I want to do is to access the button from the orange square (my custom ListFragment class) to set a click listener. I have made my research and I know I can do it (I have succesfully tried) from the adapter, but that's what I don't want, because in other menus I'm going to have other buttons that behave different but they're going to call same listener because they are built by same adapter.
I have tried after inflating the Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.menu_list, null);
//Button of location settings
((ImageButton)fragmentView.findViewById(R.id.row_button)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Do here stuff I want to
}
});
super.onStart();
return fragmentView;
}
Also from onStart:
#Override
public void onStart() {
//Button of location settings
((ImageButton)getView().findViewById(R.id.row_button)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Here my stuff
}
});
super.onStart();
}
and also after the setListAdapter()
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//A new instance of my own ListAdapter
MyListAdapter adapter = new MyListAdapter(getActivity());
//Prepare my items and its propierties within adapter
//...
//Set the Adapter
setListAdapter(adapter);
//And then try to get the Button view
//Button of location settings
((ImageButton)getView().findViewById(R.id.row_button)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//My stuff here
}
});
}
But guess what... I always get same error in xml inflating the fragment. If I remove the lines of setting the click listener, it works, but obviously the button does nothing.
Any help is greatly appreciated.
Here is the answer from the comments :
Your button is located in a row of your ListView, so you can only find it from your list adapter (in getView()). Calling findViewById() from your fragment can't return views contained in your ListView.
One solution is to set a tag to your button when you inflate it, and then do something depending on the tag when the button is clicked.
this is the activity
public void onListItemClick(ListView parent, View v,int position, long id) {
String str;
if (nRowSelected>=0) {
View row=parent.getChildAt(nRowSelected);
if (row!=null) {
row.setBackgroundColor(0xFFFFFFFF);
}
}
nRowSelected=position;
v.setBackgroundColor(Color.GRAY);
}//onListItemClick
this is my listview
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="425dp"
>
</ListView>
i need highlight single choice. i choose/focus row number 1. but when i scroll, the focus is more than one. the row focus in row 8 too
this is the capture
and
how to fix that?
You are fighting the way Adapter's recycle the row layouts... You need to extend your current Adapter and override getView() to highlight the correct row (and only the correct row).
At the most basic level it would look like:
public View getView(...) {
View view = super.getView(...);
if(position == mRowSelected) {
view.setBackgroundColor(Color.GRAY);
}
else { // You must use a default case to "un-highlight" the reused layout
view.setBackgroundColor(0xFFFFFFFF);
}
return view;
}
Add this to the xml:
android:cacheColorHint="#00000000"
Replace your xml code with following::
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="425dp"
android:cacheColorHint="#00000000">
</ListView>
Hi Please see the below code might be help it is single choice selection example follow this it work good .
public class List17 extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Use the built-in layout for showing a list item with a single
// line of text whose background is changes when activated.
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_activated_1, mStrings));
getListView().setTextFilterEnabled(true);
// Tell the list view to show one checked/activated item at a time.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Start with first item activated.
// Make the newly clicked item the currently selected one.
getListView().setItemChecked(0, true);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// Make the newly clicked item the currently selected one.
getListView().setItemChecked(position, true);
}
private String[] mStrings = Cheeses.sCheeseStrings;
}
This is list activity it does't matter that you have list view or list activity.
I am developing an Android app and one of its use cases is to display the following situation.
I have a list of links (L). Each of these links is the URL for a
picture in the Internet;
I have to download each picture of (L) and display it in a ListView. There should be two rows in the ListView(s), where I can insert the pictures. I want to do something similar to this app;
I have to display the pictures in a HorizontalScrollView;
The pictures have to be downloaded on demand, in other words, I just
download the picture using a Thread when the HorizontalScrollView is
in a position that shows this picture (similar to this
situation).
My questions:
Is it possible to insert an ListView in a HorizontalScrollView? (If yes, how do I do it?)
How do I use HorizontalScrollView? I mean, is there any difference on how I use a ListView inside a ScrollView?
Do you know any plugin/project that has the same purposes?
Question 1 - Perhaps you should re-think your design to use a list of HorizonzalListView.
Question 2 - You can created a list of HorizontialListView programmatically, place them inside a LinearLayout wrapped by a vertical scroll view.
Your myhlist.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="#+id/list_of_hlist_placeholder"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"/>
</ScrollView>
You activity:
public class ListOfHListlActivity extends Activity {
/** List of ArrayAdapter with each bind to a HorizontialListView created programmatically */
private List<MyAdapter> myAdapters = new ArrayList<MyAdapter>();
/** List of your data model */
private List<Object> myDataList;
/**
* Worker thread running in background doing dirty job.
*/
private class DoDirtyJobAsyncTask extends AsyncTask<Void, MyAdapter, Void> {
#Override
protected Void doInBackground(Void... params) {
// do your dirty job here, to populate myDataList
for (Object myData : myDataList) {
MyAdapter myAdapter = new MyAdapter(myData);
myAdapters.add(myAdapter);
publishProgress(myAdapter);
}
return null;
}
#Override
protected void onProgressUpdate(MyAdapter... myAdapters) {
int currViewId = 1;
for (final MyAdapter myAdapter: myAdapters) {
HorizontialListView listview = new HorizontialListView(getApplicationContext(), null);
listview.setId(currViewId);
listview.setAdapter(myAdapter);
listview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// I am clickable.
}
});
RelativeLayout listOfHListLayout = (RelativeLayout) findViewById(R.id.list_of_hlist_placeholder);
// don't forget set height here, you know the height issue in HorizontialListView
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT, 40);
listOfHListLayout.addView(listview, layoutParams);
currViewId++;
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new DoDirtyJobAsyncTask().execute();
setContentView(R.layout.myhlist);
}
}
You might be interested in this project http://www.dev-smart.com/archives/34
It talks about implementing the Horizontal ListView in Android without the center locking of the Gallery widget
May be its too late but now android has RecylerView which is way more efficient than Listview and also supports horizontal scroll.
My application consists of 2 activities.The first activity contains a TextView,if you click on it, you move to the second activity that consists of a ListView and a button Done. The ListView contains TextViews with a CheckBox. If you click on button then it finish activity and returns selected text item. If you go back to the list view the selected checkboxes restored.
Code would be appreciated.
First of all I suggest you to use CheckedTextView control instead of a CheckBox & TextView. CheckedTextView serves as the combination of checkbox and textview and is easy to handle and implement.
Secondly, you should have an ArrayList of boolean of the exact size as the ListView no. of Items. Then you can set the ArrayList items accordingly in the OnListItemClick function of ListView. At any time and anywahere in your code, you can get the reference of your selection of the ListView. Its simple and efficient.
Here is a sample OnListItemClick code:
#Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
arrCheckBox.set(position, !arrCheckBox.get(position));
CheckedTextView ctvListItem = (CheckedTextView)v.findViewById(R.id.ctvCustomLVRowID);
ctvListItem.setChecked(arrCheckBox.get(position));
}
Here arrCheckBox is a boolean ArrayList which is keeping record of our selection and size of this array is same as no. of ListItems. I hope now you can figure it out.
XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/LinearLayout01"
android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<ListView android:id="#+id/ListView01" android:layout_height="wrap_content"
android:layout_width="fill_parent"></ListView>
</LinearLayout>
Java code:
public class ListViewMultipleChoiceExample extends Activity {
private ListView lView;
private String lv_items[] = { "Android", "iPhone", "BlackBerry",
"AndroidPeople", "J2ME", "Listview", "ArrayAdapter", "ListItem",
"Us", "UK", "India" };
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
lView = (ListView) findViewById(R.id.ListView01);
// Set option as Multiple Choice. So that user can able to select more
// the one option from list
lView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_multiple_choice, lv_items));
lView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
}