I have a HorizontalScollView. It has a LinearLayout child. How do I populate the linear layout with children created based on content from a database since I can't bind a SimpleCursorAdapter to it (obviously)?
I've tried:
SimpleCursorAdapter summaryItems = new SimpleCursorAdapter(this, R.layout.summary_item, summaryItemsCursor, from, to);
int count = summaryItems.getCount();
View new_view;
for (int i = 0; i < count; i++) {
new_view = (summaryItems.newView(this, summaryItemsCursor, mNewsContainer));
mNewsContainer.addView(new_view);
}
I was hoping that the view returned by the SimpleCursorAdapter.newView() would be usable, but apparently not. I'm quite new to android and completely lost as to the right way to do this.
XML's for reference:
<HorizontalScrollView android:id="#+id/news_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:id="#+id/news_container"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
>
</LinearLayout>
</HorizontalScrollView>
and summary_item
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/news_gallery_item"
android:layout_marginRight="#dimen/news_gallery_item_spacing"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/news_gallery_item_image"
android:adjustViewBounds="true"
android:maxHeight="#dimen/news_gallery_image_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/news_gallery_item_tagline"
style="#style/news_gallery_text_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
This sounds (and somehow looks) like you'll want to use a ListView. A tutorial might be found here.
To populate the ListView, you can then use a SimpleCursorAdapter.
Since you need it horizontally, you can use the HorizonatalListView-class, which is a user-created extension to a normal ListView (so you can use all it's methods). The corresponding question can be found here.
A ViewBinder with an Inflater on your item view should do the trick
Related
I have a listview containing some news. Each news is a row which comtains a title, content, publisher and date. Now I want to set hyperlinks to every title TextView. How to implement that? The following is my code:
private void show_news() {
ArrayList<Map<String, Object>> list = new ArrayList<>();
get_data(list);
ListView lv = (ListView) findViewById(R.id.News_List);
SimpleAdapter adp = new SimpleAdapter(getApplicationContext(), list, R.layout.news_item, new String[]{"news_title", "news_content", "news_publisher", "news_date"}, new int[]{R.id.news_title, R.id.news_content, R.id.news_publisher, R.id.news_date});
lv.setAdapter(adp);
/* the code above runs properly*/
/*Now I want to set hyperlink to my title TextView..*/
}
This is my news_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/news_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:textColor="#000000"
android:textSize="25sp" />
<TextView
android:id="#+id/news_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:textSize="18sp" />
<TextView
android:id="#+id/news_publisher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:textSize="12sp" />
<TextView
android:id="#+id/news_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp" />
</LinearLayout>
I am new to Android programming. Can anyone help me with this? Thanks a lot!
LinearLayout first = (LinearLayout) adp.getView(0, null, lv);
TextView title = (TextView)first.getChildAt(0);
That doesn't necessarily get the first element of the list view. It doesn't even necessarily get the first element on screen. That's very implementation specific (you're assuming the list view doesn't have any children other than its rows, which is actually wrong in many cases).
If you want to change the first item of a list view, do
Item item = adb.getItem(0)
item.title= "New Title"
adp.notifyDataSetChanged();
You can extend the SimpleAdapter and use the derived adapter. When you extend the adapter, set the hyperlink property for the title by calling:
<the title textview>.setAutoLinkMask(Linkify.WEB_URLS);
in the method getView method of the adapter. A commonly used approach in Android ListView adapter is to use a so called view holder, which is a key technique to get better listview performance, and you can check the details from the developer document: Hold View Objects in a View Holder
Suppose you employ this approach, the code would looks more or less like:
holder.titleView.setAutoLinkMask(Linkify.WEB_URLS);
If your textview does not have a URL, then you can set the text in HTML form as:
holder.titleView.setText(
Html.fromHtml(
"Breaking News "));
holder.titleView.setMovementMethod(LinkMovementMethod.getInstance());
I created a custom component called ScrollListView, which is basically a table, extending ListView. Using the function getView below, I fill this component with the data coming from the database. It works perfectly and the result is visually that:
Obviously I would like the cells were aligned, like this:
To achieve this, currently I perform the calculations to measure all the cell sizes, and then adjust the column based on the widest cell, but GC is called several times, causing lag during scrolling, as previously reported is this thread
My question is: how to automatically fix/measure the size of the columns, without crazy calculations called in every getView call, extinguishing all those GC occurrences? I've tried to extend the GridView instead ListView, but it did not work. I´m new on Android.
(I CAN NOT use a standard component, such as GridView or GridLayout, I MUST use my custom component ScrollListView due to other more complex functions that currently operate correctly)
Thanks in advance and sorry for my bad english
Edit: Here is my code (the getView code is in the thread already mentioned):
scroll_listview.xml
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="#color/BackGroundColor"
android:scrollbars="none" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<TableLayout
android:id="#+id/header_lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
</TableLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<android.ListView
android:id="#+id/rows_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="0dip"
android:divider="#null"
android:dividerHeight="0dp"
android:padding="0dip"
android:scrollbars="horizontal"
android:gravity="center_horizontal"
android:stretchColumns="*"
/>
</LinearLayout>
</LinearLayout>
</HorizontalScrollView>
And my ScrollListView.java
public class ScrollListView extends LinearLayout
{
TableLayout header;
ListView rows;
public ScrollListView(Context context, AttributeSet attrs)
{
super(context, attrs);
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view=layoutInflater.inflate(R.layout.scroll_listview,this);
if (!this.isInEditMode())
{
rows = (ListView)this.findViewById(R.id.rows_lv);
header = (TableLayout)this.findViewById(R.id.header_lv);
rows.setOnRedrawListener(new OnListViewRedraw() {
#Override
public void onBeforeRedraw() {
}
#Override
public void onAfterRedraw() {
}
});
rows.setHeader(header);
rows.setMyParent(this);
}
// (and so on...)
Check out the TableLayout.onMeasure() source code. They find the widths of the cells for all children, then adjusts all children to match accordingly. You will need some modified version of this to fit your needs.
Basically, I need some rows to be 3 lines and others for the text to be centered on the middle line. I already have the 3 lines working. I just need to figure out how to check if the lines R.id.text2 and R.id.text3 are empty and set TAG_1 to be displayed on R.id.text2. I'm posting what I think it relevent. If more code is needed just let me know
ListAdapter simpleAdapter = new SimpleAdapter(this, makeList,
R.layout.custom_list_view,
new String[] { TAG_1, TAG_2, TAG_3 }, new int[] { R.id.text1, R.id.text2, R.id.text3 });
listView.setAdapter(simpleAdapter);
custom_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="19sp"/>
<TextView android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"/>
<TextView android:id="#+id/text3"
android:layout_width="wrap_content"
android:layout_height="fill_parent"/>
</LinearLayout>
SimpleAdapter is pretty useless for displaying anything but the most basic list. You will have much more success extending your own adapter. Start with an ArrayAdapter.
The basic concept is that you extend the adapter and implement its getView() function. In this you inflate (or reuse) a view for each row and populate it with your data.
There are many adapter tutorials on the internet, I found this one with a quick search.
Understanding how to utilize adapters is a fundamental part of android development.
I'm pretty new on android, i'm currently reading a lot of documentation to understand how to start. I've tried to search before asking here but i'm not able to find relevant information.
My problem is have 2 listview in the same acivity.
The Listview A with a list of category.
The Listview B with a details data (at startup the values showed are based on the category 1 of the listviewA)
When a click on a item of the listviewA the data of the listViewB change to reflect the new selection and show the new list of details data.
Can someone give me the right direction or a link to a tutorial that cover this topic ?
Sorry i'm not able to post any code at the moment.
I am not sure that the type of layout you are trying to make is user friendly. It would give the users far more richer UI experience if you change with an ExpandableListView. You can check out a tutorial here. Using this would give you the chances of engaging the user via an interaction.
Anyway, if you are sure to go with ListView then simply create a root LinearLayout and within this you take two ListViews. But taking the second one as a listview does not make sense. Rather, instead of making the second control a ListView, take a TextView to show the details.Provide the height of both layouts (ListView and TextView) according to your requirement.
Look at this tutorial
2 Listviews:
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:baselineAligned="false" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<ListView
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:visibility="visible">
</ListView>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" >
<ListView
android:id="#+id/listView2"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:visibility="visible">
</ListView>
</LinearLayout>
</LinearLayout>
1 ListView 1 TextView:
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:baselineAligned="false" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<ListView
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:visibility="visible">
</ListView>
</LinearLayout>
<TextView android:id="#+id/TextView1" android:text="details"/>
</LinearLayout>
UPDATE:
Please explain your problem a bit more. Because, in your scenario the data between the list views is connected with each other. Say, if ListView A is about Products so ListView B is about ProductDetails. So you need to declare a class variable say ProductID which is common entity between both data and set this variable setOnClickListener in ``getView()` of ListView A and fetch the data regarding this just after that and set the Adapter of ListView B with the results of this query (which may be to SQL db or RESTful server).
I have used this strategy before and it worked out well for me.
Use a linear layout to position the two list views, Populate the 'category' listview and set a list adaptor for it. On this listview I set an OnItemSelectedListener which when activated set ups the list-adaptor on the second 'detail' view.
Depending on your exact need you can either replace the detail listview's adapter or just change the content the adapter looks at and tell it to refresh.
Try this:
After get listview by id (list_A) set click listener
list_A.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//here you can get click position from parameter position
// and do somthing in Adapter_B and then call notifyDataSetChanged() for Adapter_B
Adapter_B.notifyDataSetChanged();
}
});
currently i have the following layout
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_marginTop="9px"
android:layout_below="#+id/desc"
android:id="#+id/ll_item"
android:orientation="vertical"
android:paddingRight="3px"
android:paddingLeft="3px"
android:paddingBottom="5px"
android:paddingTop="5px"
android:background="#drawable/rounded_corner_lists" >
<!--
<ListView android:drawSelectorOnTop="false" android:id="#+id/lv" android:layout_height="fill_parent" android:layout_width="wrap_content" android:divider="#ddd" android:dividerHeight="1px" android:background="#drawable/white" />
-->
</LinearLayout>
the listview that i have commented out, i have tried to make this in the xml, with the height set to wrap_content, fill_parent, currently i am doing this programatically with the following code
LinearLayout ll_item = (LinearLayout) this.findViewById(R.id.ll_item);
if(list.length() > 0)
{
ll_item.setVisibility(View.VISIBLE);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,calcListHeight(list));
listview = new ListView(this);
listview.setBackgroundResource(R.drawable.white);
listview.setDivider( new ColorDrawable(this.getResources().getColor(R.drawable.dividercolor)) );
listview.setDividerHeight(1);
listview.setCacheColorHint(0);
mAdapter = new JSONAdapter( list, this );
listview.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
ll_item.addView(listview, lp);
}
this is the result
so you can see in this image, that since i'm containing the listview in a linearlayout to get the rounded corner look, it doesn't just automatically stretch to contain the entire listview, is there any way to have the two elements just wrap the content vertically so there is no scrolling without me programatically setting the height ? ? ?
i guess one other thing i should mention is that i have all this layout in a scrollview, because i want this listview to be a tiny subsection of the entire layout, so it would be something like
-scrollview
-textview
-textview
-linearlayout
-listview
- button
here is a simpler layout of what i have
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent"
android:background="#drawable/bg" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/titlebar">
<ScrollView android:id="#+id/sv" android:layout_width="fill_parent" android:background="#drawable/bg"
android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout android:id="#+id/widget28"
android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="4dip"
>
<LinearLayout android:orientation="vertical" style="#style/rounded_corner_full_width_button"
android:id="#+id/editfields">
<ListView android:drawSelectorOnTop="false" android:id="#+id/lv" android:layout_height="fill_parent"
android:layout_width="wrap_content" android:divider="#ddd" android:dividerHeight="1px"
android:background="#drawable/white"/>
</LinearLayout>
</RelativeLayout>
</ScrollView>
</LinearLayout>
ListViews do not go in ScrollViews.
ListView is for displaying a limited window into unbounded content efficiently. If you were to "disable scrolling" on a ListView to put it within a ScrollView you lose all practical reason for using a ListView in the first place.
If you want to use a ListView to show lots of content or unbounded content but also have content above and below that scrolls with it, add header or footer views to the ListView using addHeaderView or addFooterView. If the list content is going to be a small portion of your overall layout as you describe, this probably isn't the best approach for you.
If you have a small, bounded set of content to present, go ahead and use a ScrollView and programmatically generate child views for your "list items" where appropriate.
A common pattern used in the framework to mix inflated XML content with programmatically generated content is to add a placeholder view in the layout XML, usually a LinearLayout or FrameLayout. Use findViewById to locate it at runtime and add generated child views to it.
You could even still use a ListAdapter with this approach if you have one written already, just call content.addView(adapter.getView(position, null, content)) in a loop for all adapter positions (where content is the placeholder view you located with findViewById). Note that this is only practical if you know that you have a small number of list items in the adapter!
Add a empty item on list end
Example:
ArrayList<String> options = new ArrayList<String>();
String lastItem = "";
int lastPosition;
options.add(lastItem);
public function addItem() {
lastPosition = options.size() - 1;
lastItem = options.get(lastPosition);
options.remove(lastPosition);
//add new items dynamically
for (int i = 0; i < 5; i++)
options.add("new item: "+i);
//add empty item
options.add(lastItem);
}