This question already has answers here:
ListView inside ScrollView is not scrolling on Android
(27 answers)
Closed 3 months ago.
I want to set listview to show all items without scroll.
Below is my layout:
<LinearLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Large Text"
android:textColor="#android:color/black"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<TextView
android:id="#+id/tv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Large Text"
android:textColor="#android:color/black"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
The linearlayout is belong to a scrollview.
So I want to set the listview all items and scroll by the parent's scroll.
How can I do it?
If the reason for this requirement is similar to what I needed, the class below can help. It is a replacement ListView, one that observes an adapter and its changes and reacts accordingly, but uses a manually populated LinearLayout under the hood, actually. I guess I found this code somewhere on the net but I couldn't locate it now in order to link to it.
My requirements were to use the advantages of a ListView, namely its adapter functionality, to display a very few items (1 to 5) on a page, with possibly more than one such replacement ListView on a single screen. Once displayed, the elements themselves become part of the larger page, so they aren't scrolled separately inside their own ListView, rather with the page as a whole.
public class StaticListView extends LinearLayout {
protected Adapter adapter;
protected Observer observer = new Observer(this);
public StaticListView(Context context) {
super(context);
}
public StaticListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setAdapter(Adapter adapter) {
if (this.adapter != null)
this.adapter.unregisterDataSetObserver(observer);
this.adapter = adapter;
adapter.registerDataSetObserver(observer);
observer.onChanged();
}
private class Observer extends DataSetObserver {
StaticListView context;
public Observer(StaticListView context) {
this.context = context;
}
#Override
public void onChanged() {
List<View> oldViews = new ArrayList<View>(context.getChildCount());
for (int i = 0; i < context.getChildCount(); i++)
oldViews.add(context.getChildAt(i));
Iterator<View> iter = oldViews.iterator();
context.removeAllViews();
for (int i = 0; i < context.adapter.getCount(); i++) {
View convertView = iter.hasNext() ? iter.next() : null;
context.addView(context.adapter.getView(i, convertView, context));
}
super.onChanged();
}
#Override
public void onInvalidated() {
context.removeAllViews();
super.onInvalidated();
}
}
}
Do not put listview inside a scrollview.
http://developer.android.com/reference/android/widget/ScrollView.html
Quoting from docs
You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.
You can add your textview's as a header and footer to listview.
http://developer.android.com/reference/android/widget/ListView.html
Check the header and footer methods in the above link
You can have a relative layout add textviews at the top and bottom. Relative to the textviews have the listview between the textview's
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="TextView1" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView1"
android:layout_alignParentBottom="true"
android:text="TextView1" />
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/textView1"
android:layout_above="#+id/textView2"
>
</ListView>
</RelativeLayout>
I think it is not possible. If we override list view scroll behavior using parent layout scroll,list view did not work properly.
Related
I am new to Android development and feel like this is a really trivial problem, but I cannot word it well enough to find a solution online, so I might as well ask the question here.
My goal is to create a reusable component that is essentially an expandable card like the one described here: https://material.io/design/components/cards.html#behavior.
To do it, I created a custom view that extends a CardView:
public class ExpandableCardView extends CardView {
public ExpandableCardView(Context context) {
super(context);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
// get custom attributes
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, 0, 0);
String heading = array.getString(R.styleable.ExpandableCardView_heading);
array.recycle();
// inflate the layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.expandable_card_view, this, true);
// set values
TextView headingTextView = findViewById(R.id.card_heading);
headingTextView.setText(heading.toUpperCase());
// set collapse/expand click listener
ImageView collapseExpandButton = findViewById(R.id.collapse_expand_card_button);
collapseExpandButton.setOnClickListener((View v) -> toggleCardBodyVisibility());
}
private void toggleCardBodyVisibility() {
LinearLayout description = findViewById(R.id.card_body);
ImageView imageButton = findViewById(R.id.collapse_expand_card_button);
if (description.getVisibility() == View.GONE) {
description.setVisibility(View.VISIBLE);
imageButton.setImageResource(R.drawable.ic_arrow_up);
} else {
description.setVisibility(View.GONE);
imageButton.setImageResource(R.drawable.ic_arrow_down);
}
}
}
And the layout:
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/expandable_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_header"
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal" >
<TextView
android:id="#+id/card_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#color/colorPrimary"
android:layout_alignParentLeft="true"
android:text="HEADING"/>
<ImageView
android:id="#+id/collapse_expand_card_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
app:srcCompat="#drawable/ic_arrow_down"/>
</RelativeLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_body"
android:padding="12dp"
android:layout_marginTop="28dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="gone" >
</LinearLayout>
</androidx.cardview.widget.CardView>
Ultimately I want to be able to use it like so in my activities, usually multiple instances per activity:
<xx.xyz.yy.customviews.ExpandableCardView
android:id="#+id/card_xyz"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom_xxx:heading="SOME HEADING" >
<SomeView></SomeView>
</xx.xyz.yy.customviews.ExpandableCardView>
Where SomeView is any text, image, layout or another custom view altogether, typically with data bound from the activity.
How do I get it to render SomeView inside the card body? I want to take whatever child structure is defined within the custom view and show it in the card body when it is expanded. Hope I made it easy to understand.
I think that a better approach would be to define the layout that will be inserted into the CardView ("SomeView") in a separate file and reference it with a custom attribute like this:
<xx.xyz.yy.customviews.ExpandableCardView
android:id="#+id/card_xyz"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom_xxx:heading="SOME HEADING"
custom_xxx:expandedView="#layout/some_view"/>
I'll explain my rationale at the end, but let's look at an answer to your question as stated.
What you are probably seeing with your code is SomeView and expandable_card_view appearing all at once in the layout. This is because SomeView is implicitly inflated with the CardView and then expandable_card_view is added through an explicit inflation. Since working with layout XML files directly is difficult, we will let the implicit inflation occur such that the custom CardView just contains SomeView.
We will then remove SomeView from the layout, stash it, and insert expandable_card_view in its place. Once this is done, SomeView will be reinserted into the LinearLayout with the id card_body. All this has to be done after the completion of the initial layout. To get control after the initial layout is complete, we will use ViewTreeObserver.OnGlobalLayoutListener. Here is the updated code. (I have removed a few things to simplify the example.)
ExpandableCardView
public class ExpandableCardView extends CardView {
public ExpandableCardView(Context context) {
super(context);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
// Get control after layout is complete.
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove listener so it won't be called again
getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Get the view we want to insert into the LinearLayut called "card_body" and
// remove it from the custom CardView.
View childView = getChildAt(0);
removeAllViews();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.expandable_card_view, ExpandableCardView.this, true);
// Insert the view into the LinearLayout.
((LinearLayout) findViewById(R.id.card_body)).addView(childView);
// And the rest of the stuff...
TextView headingTextView = findViewById(R.id.card_heading);
headingTextView.setText("THE HEADING");
// set collapse/expand click listener
ImageView collapseExpandButton = findViewById(R.id.collapse_expand_card_button);
collapseExpandButton.setOnClickListener((View v) -> toggleCardBodyVisibility());
}
});
}
private void toggleCardBodyVisibility() {
LinearLayout description = findViewById(R.id.card_body);
ImageView imageButton = findViewById(R.id.collapse_expand_card_button);
if (description.getVisibility() == View.GONE) {
description.setVisibility(View.VISIBLE);
imageButton.setImageResource(R.drawable.ic_arrow_up);
} else {
description.setVisibility(View.GONE);
imageButton.setImageResource(R.drawable.ic_arrow_down);
}
}
}
expandable_card_view.java
The CardView tag is changed to merge to avoid a CardView directly nested within a CardView.
<merge
android:id="#+id/expandable_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp">
<RelativeLayout
android:id="#+id/card_header"
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal" >
<TextView
android:id="#+id/card_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#color/colorPrimary"
android:layout_alignParentLeft="true"
android:text="HEADING"/>
<ImageView
android:id="#+id/collapse_expand_card_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
app:srcCompat="#drawable/ic_arrow_down"/>
</RelativeLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_body"
android:padding="12dp"
android:layout_marginTop="28dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="gone" >
</LinearLayout>
</merge>
activity_main.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.customcardview.ExpandableCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_android" />
<TextView
android:id="#+id/childView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name."
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.example.customcardview.ExpandableCardView>
</LinearLayout>
So, why do I suggest that you use a custom attribute to include SomeView in the layout as I identified at the beginning? In the way outlined above, SomeView will always be inflated and there is some effort to switch the layout around although SomeView may never be shown. This would be expensive if you have a lot of custom CardViews in a RecyclerView for instance. By using a custom attribute to reference an external layout, you would only need to inflate SomeView when it is being shown and the code would be a lot simpler and easier to understand. Just my two cents and it may not really matter depending upon how you intend to use the custom view.
I am implementing a RecyclerView inside a ScrollView. In order to have only one scrolling behaviour on the entire page I implement a NonScrollRecyclerView version. The implementation is as follows:
public class NonScrollRecyclerView extends RecyclerView {
public NonScrollRecyclerView(Context context) { super(context); }
public NonScrollRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
if(ev.getAction() == MotionEvent.ACTION_MOVE)
return true;
return super.dispatchTouchEvent(ev);
}
}
Once i update my build and target settings to SDK 23, I have trouble scrolling the page which contains the NonScrollRecyclerView. The specific problem is that the page scrolls OK until i reach the recycler view portion and once i scroll onto this view I am unable to scroll anymore, either up or down.
I DONOT face this problem with SDK 22 and below
My xml is as follows:
XML #layout/rv contains the recycler view
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_gray">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background_gray"
android:orientation="vertical">
<include
layout="#layout/row_mall_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_header"
android:layout_marginTop="8dp"/>
<include
layout="#layout/row_mall_shops"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_shops"
android:layout_marginTop="8dp"/>
<include
layout="#layout/row_mall_coupons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_coupons"
android:layout_marginTop="8dp"/>
<include
layout="#layout/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_feeds"
android:layout_marginTop="8dp"/>
</LinearLayout>
</ScrollView>
XML - #layout/rv
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_gray"
android:id="#+id/ll_mall_feeds">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:paddingTop="6dp"
android:paddingBottom="6dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_feedcount"
android:textColor="#color/semi_theme_blue"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="12dp"
android:layout_centerVertical="true" />
</RelativeLayout>
<com.project.ui.NonScrollRecyclerView
android:id="#+id/nrv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#android:color/transparent"
android:listSelector="#android:color/transparent" />
</LinearLayout>
RecyclerView and ListView are not recommended inside a ScrollView because elements hights are not calculated when rendering the ScrollView. This means, your adapter might not be populated when the ScrollView is shown and later when the RecyclerView is notified about data changes (for instance when you initialize your adapter), there's not way to recalculate the elements heights.
It's really a pain in the neck because you have to try to calculate the elements heights and it's never accurate, so you will have discrepancies when showing a ListView or a RecyclerView inside a ScrollView. Some examples of how to calculate the elements heights can be checked here and here.
My advice is to turn your RecyclerView into a LinearLayout and add elements programmatically, so you emulates the ListView or RecyclerView behaviour:
LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.files);
layout.removeAllViews();
for (int i = 0; i < fileAdapter.getCount(); i++) {
final View item = fileAdapter.getView(i, null, null);
item.setClickable(true);
item.setId(i);
item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fileContentRowPosition = v.getId();
# Your click action here
}
});
layout.addView(item);
}
Here its the XML with the files definition:
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<LinearLayout
android:id="#+id/files"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
The whole java code can be checked here and the whole Layout here.
On the other hand, if you still want to continue with your implementation, and regarding your issue, you can check this article about Handling Scrollable Controls in Scrollview
Best regards,
For only one scrolling in the entire page you can use NestedScrollView instead of ScrollView and set recyclerView.setNestedScrollingEnabled(false);
I am trying to modify my ListView so that it:
Contains an image
Contains a text description (fileName)
Contains a check box.
The list should be multi selectable. And I should be able to loop through all the checked checkboxes and get the description.
Currently, I can display an ordinary ListView with check boxes.
ArrayAdapter<String> ad = new ArrayAdapter<String>(HelloDropboxActivity.this, android.R.layout.simple_list_item_multiple_choice,fileName);
mTestListOutput.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mTestListOutput.setAdapter(ad);
Using the onClick of a Button - I can loop through the checked boxes and get the text into an ArrayList like this:
ArrayList<String> dbLinks = new ArrayList<String>();
int cntChoice = mTestListOutput.getCount();
SparseBooleanArray sparseBooleanArray = mTestListOutput.getCheckedItemPositions();
for(int i = 0; i < cntChoice; i++)
{
if(sparseBooleanArray.get(i) == true)
{
dbLinks.add(mTestListOutput.getItemAtPosition(i).toString());
}
}
I am retreving an ArrayList of :
private ArrayList paths;
So how can I tie these together to create a custom ListView?
I have looked at many examples and tried to modify them but I am getting nowhere.
Here I have attampted to create the Layout of a list row in my list_row.xnl:
<?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:orientation="horizontal"
android:padding="5dip" >
<!-- Thumbnail image -->
<LinearLayout android:id="#+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dip"
android:layout_alignParentLeft="true"
android:layout_marginRight="5dip">
<ImageView
android:id="#+id/list_image"
android:layout_width="50dip"
android:layout_height="50dip"
/>
</LinearLayout>
<!-- File Name -->
<TextView
android:id="#+id/filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title"
android:textColor="#343434"
android:textSize="10dip"
android:layout_marginTop="1dip"
android:layout_toRightOf="#+id/thumbnail"
android:text="Just gona stand there and ..." />
</RelativeLayout>
I think the problem that are having is that when the listitem is selected, it is actually being selected but you can't see any difference because the root view must implement 'Checkable'. There is way to make this work although its more complicated that I think it should be.
First of all, you need to add a the following class. This is a checkable LinearLayout that should relay the calls from the checkable interface through to the checkbox within it. It should be easy to modify this for whatever view group you want to use.
public class CheckableLinearLayout extends LinearLayout implements Checkable {
private CheckBox _checkbox;
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// find checked text view
int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View v = getChildAt(i);
if (v instanceof CheckBox) {
_checkbox = (CheckBox) v;
}
}
}
public boolean isChecked() {
return _checkbox != null ? _checkbox.isChecked() : false;
}
public void setChecked(boolean checked) {
if (_checkbox != null) {
_checkbox.setChecked(checked);
}
}
public void toggle() {
if (_checkbox != null) {
_checkbox.toggle();
}
}
}
Next define the layout of that you want to use for each item, using the CheckableLinearLayout above:
<com.myPackage.CheckableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/checkBox1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox" />
<TextView
android:id="#+id/textView1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<ImageView
android:id="#+id/imageView1"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/background_iv" />
</com.myPackage.CheckableLinearLayout>
Then, alter the line that creates the Adapter so that the ID of the layout above is used instead.
I have a list view which contains some 20 odd items from database along with a two Buttons and an extra TextView as a counter enclosed within linear layout. The two buttons usually for increment and decrement the value in an extra TextView. What i want is when i press button outside the listView should fetch all items along with an value of an extra text. Right now I can fetch Linear layouts and there child items which are visible on screen i.e. out 20 items 10 are visible on screen, so my question is how to fetch the remaining items along with extra Textview values enclosed within linear layout which are not visible which can be viewed when we scroll the Listview?
Here is main.xml file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation= "horizontal"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#CBCBCB">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/widget64"
android:background="#drawable/toolbar_color"
android:layout_x="0px"
android:layout_y="0px"
android:layout_width="match_parent" android:layout_height="40dip">
<Button
android:id="#+id/save_creature_for_encounter"
android:layout_marginTop="5px"
android:textSize="10dip"
android:textColor="#ffffff"
android:textStyle="bold"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:background="#drawable/onclick_button_bg"
android:layout_width="40dip" android:layout_height="50dip"
android:text="Save"/>
<Button
android:id="#+id/back_show_encounter"
android:layout_width="80dip"
android:layout_marginTop="5px"
android:text="Cancel"
android:textSize="10dip"
android:textColor="#ffffff"
android:textStyle="bold"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:background="#drawable/button_color"
android:layout_height="50dip">
</Button>
</RelativeLayout>
<ListView
android:id="#+id/list_view"
android:background="#ffffff"
android:fadingEdge="none"
android:cacheColorHint="#ffffff"
android:layout_weight="1"
android:layout_gravity="center"
android:scrollbars="vertical"
android:layout_marginTop="28dip" android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
And here is my custom_list.xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="left|center"
android:paddingBottom="5px"
android:paddingTop="5px" android:paddingLeft="5px" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView android:text="test" android:id="#+id/item_creatures_to_encounter"
android:layout_marginLeft="10px" android:layout_width="180dip" android:layout_height="wrap_content"></TextView>
<Button
android:id="#+id/desc"
android:layout_width="30px"
android:layout_height="30px"
android:layout_marginTop="5px"
android:text="-"
android:textSize="10dip"
android:textColor="#ffffff"
android:textStyle="bold"
android:layout_alignTop="#+id/widget66"
android:layout_alignParentRight="true"
android:onClick="myDescClickHandler">
>
</Button>
<Button
android:id="#+id/asc"
android:layout_width="30px"
android:layout_height="30px"
android:layout_marginTop="5px"
android:text="+"
android:textSize="10dip"
android:textColor="#ffffff"
android:textStyle="bold"
android:layout_alignTop="#+id/widget66"
android:layout_alignParentRight="true"
android:onClick="myAscClickHandler">
>
</Button>
<TextView android:text="#string/counter" android:id="#+id/counter"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip" android:layout_width="30dip"></TextView>
</LinearLayout>
Here is my custom Adapter file
public class DomainAdapter extends SimpleCursorAdapter{
private LayoutInflater mInflater;
public DomainAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
mInflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent, Cursor data) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
//final ViewHolder holder;
View row = super.getView(position, convertView, parent);
ViewHolder holder=(ViewHolder)row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
holder.add = (Button) row.findViewById(R.id.asc);
Button.OnClickListener b =
new Button.OnClickListener() {
public void onClick(View v) {
LinearLayout parent = (LinearLayout)v.getParent();
TextView label=(TextView)parent.findViewById(R.id.counter);
Log.d("AAAAJJJAAA", ""+ parent);
CharSequence value = ((TextView) label).getText();
int count = Integer.parseInt((String) value);
count++;
String inc = String.format("%d", count);
label.setText(inc);
//parent.refreshDrawableState();
}
};
holder.add.setOnClickListener(b);
}
return row;
}
}
The Views that are outside the visible area does not exists. ListView creates only the amount of views that are on the screen.
When you scroll, and a View disappears it reuses that View. It actually asks for the Adapter to modify the parameters of the View and it uses the modified View.
Example:
Let view1 be your first row (the one that's text is avatar). When you scroll down, "avatar" disappears and a new one becomes visible at the bottom. The ListView doesn't need view1 anymore, because it is not visible. So it gives view1 to the Adapter and asks it to modify view1's parameters to be the new row. The adapter sets the text on view1 to the next row (eg. "human") and returns it to the ListView. The ListView will display the view1 at the bottom of the list.
So basically the views that are outside the visible area doesn't exists.
What you can do: save the count to the adapter when a user presses the + or - buttons.
Then you can ask for the data items (listView.getItemAtPosition(int position)) and count those.
Code sample for this:
class DataForView {
int counter;
}
ListView mListView;
...
int sumCounter = 0;
for (int i=0; i<mListView.getCount(); i++) {
sumCounter += ((DataForView)mListView.getItem(i)).counter;
}
Look at the following tutorial for custom Adapters:
http://commonsware.com/Android/excerpt.pdf
List view doesn't contain ALL the children. When you scroll it, it creates only visible items on run time. 2. If you want to get all the children altogether, Better keep an ArrayList of the child objects that your list has. You can add or remove children to this ArrayList as per requirement.
get the ListView's adapter instance and then try calling getItem ( http://developer.android.com/reference/android/widget/Adapter.html#getItem%28int%29)
I have a very basic ListView in android and had set a very basic adapter. My problem is that the list view does not show anything, regardless of the adapter and the notifyDataSetChanged();
Here is my code:
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
></TextView>
<ListView android:id="#+id/selectView"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</ListView>
</RelativeLayout>
The Activity code:
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import com.androidcourse.phonemapper.R;
import com.androidcourse.phonemapper.model.SelectViewAdapter;
public class SelectActivity extends Activity {
private ListView mListView;
private SelectViewAdapter mAdapter;
#Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
setContentView(R.layout.select_activity);
initializeListView();
}
private void initializeListView() {
mListView = (ListView) findViewById(R.id.selectView);
mAdapter = new SelectViewAdapter(this);
mListView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
#Override
public void onResume() {
super.onResume();
}
}
And the Adapter code:
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SelectViewAdapter extends BaseAdapter {
private Context mContext;
private TextView mMockTextView;
public SelectViewAdapter(Context cnt) {
mContext = cnt;
mMockTextView = new TextView(mContext);
mMockTextView.setText("Test text");
mMockTextView.setBackgroundColor(Color.CYAN);
}
#Override
public int getCount() {
return 3;
}
#Override
public Object getItem(int position) {
return mMockTextView;
}
#Override
public long getItemId(int position) {
return 3;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return mMockTextView;
}
}
The problem is that nothing is shown on the screen. A black screen (and the first text view from the XML) is all I get. I cannot see the mockTextView and its text. Apparently I am doing something quite wrong, but I cant figure out what.
A few things I can think of.
First, Your RelativeLayout has no relative positioning information. I would assume you meant to put this in a LinearLayout with orientation set to vertical from what you describe. My guess is that the list is not actually being drawn since it isn't even anchored to anything in the current RelativeLayout. If you stick with the RelativeLayout, make sure to put an id on the app_name TextView and position the ListView under it via layout_below.
LinearLayout Solution
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
></TextView>
<ListView android:id="#+id/selectView"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</ListView>
</LinearLayout>
RelativeLayout Solution:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/app_name_text"
android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
></TextView>
<ListView android:id="#+id/selectView"
android:layout_below="#id/app_name_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</ListView>
</RelativeLayout>
Next, your getView() returns the same textView for all 3 indexes. It's not a problem to display the same view over multiple indexes however with a list size of three, I am betting that the screen can display all three at the same time. And since a View can't be in more than one position at a time, I actually would expect this to fail so I doubt it is even getting to this code yet. Try creating a new TextView for each getView(). Also your MockTextView doesn't have layout params of it's own. So laying it out within a listView cell might not be happening either. So you can give it params of type AbsListView.LayoutParams(WRAP_CONTENT, WRAP_CONTENT). Again though I would expect this to error if it got to the original code.
getView() tidy up:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
TextView textView = new TextView(parent.getContext());
textView.setText("Position is:"+position);
textView.setBackgroundColor(Color.CYAN);
textView.setLayoutParams(new AbsListView.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
convertView = textView;
}
return mMockTextView;
}
And lastly the wrap_content height of your list can sometimes be problematic. I am not aware of all the scenarios. If you end up changing to a LinearLayout try setting your layout_height of the list view to 0 and then set the layout_weight=1. This forces the linear layout to inflate it into more space.
LinearLayout Weight Solution:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
></TextView>
<ListView android:id="#+id/selectView"
android:layout_weight="1"
android:layout_height="0dp"
android:layout_width="wrap_content">
</ListView>
</LinearLayout>
I was using the Data Binding example from the book Hello Android by Ed Burnette (great book).
I changed the item layout from A RelativeLayout to a LinearLayout; however, I did not add an orientation when I made the change.
Once I added android:orientation="vertical" everything worked fine.
Two hours of my life on this one.
While it does not answer this question, a typical issue is to inflate as adapter resource a layout based on a parent LinearLayout with height=wrap_content and each LinearLayout element with height=fill_parent.
Like in
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/someText"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"/>
While it is displayed nicely in Eclipse, each row ends with height=0. This can be fixed by setting height=wrap_content for one of the child element
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/someText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
Could be helpfull for someone.
Make sure your adapter function getCount() is implemented and returns higher value then 0. If method returns 0, list is not shown or filled.
i had the same problem but when i changed the
ConstraintLayout
into
Relative layout
it become visible and problem solved.