I've got two ListView objects that I would like to scroll together. They are side-by-side, so if one scrolls a certain amount, the other scrolls that same amount. I've found some examples on how to do this, but I believe that they rely on the items in the ListView being the same height (correct me if I am wrong). The items in one of my ListView objects are taller than the ones in the other, spanning 2-3 items.
How do I "lock" these 2 ListView objects together?
EDIT: Here's a screenshot of what I have, maybe it will better explain what I'm going for. The left side (red) is a list of items and the right side is a separate list. You can see how the lists don't align perfectly, so it isn't exactly a grid. What I would like to do is have this act like one big list, where scrolling either list will also scroll the other.
I created a rough class that does basically what I wanted to do. It's not smart enough to handle if the 2nd list is longer than the 1st or if the orientation changes, but it's good enough to get the concept down.
To set it up:
list1.setOnScrollListener(new SyncedScrollListener(list2));
list2.setOnScrollListener(new SyncedScrollListener(list1));
SyncedScrollListener.java
package com.xorbix.util;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
public class SyncedScrollListener implements OnScrollListener{
int offset;
int oldVisibleItem = -1;
int currentHeight;
int prevHeight;
private View mSyncedView;
public SyncedScrollListener(View syncedView){
if(syncedView == null){
throw new IllegalArgumentException("syncedView is null");
}
mSyncedView = syncedView;
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int[] location = new int[2];
if(visibleItemCount == 0){
return;
}
if(oldVisibleItem != firstVisibleItem){
if(oldVisibleItem < firstVisibleItem){
prevHeight = currentHeight;
currentHeight = view.getChildAt(0).getHeight();
offset += prevHeight;
}else{
currentHeight = view.getChildAt(0).getHeight();
View prevView;
if((prevView = view.getChildAt(firstVisibleItem - 1)) != null){
prevHeight = prevView.getHeight();
}else{
prevHeight = 0;
}
offset -= currentHeight;
}
oldVisibleItem = firstVisibleItem;
}
view.getLocationOnScreen(location);
int listContainerPosition = location[1];
view.getChildAt(0).getLocationOnScreen(location);
int currentLocation = location[1];
int blah = listContainerPosition - currentLocation + offset;
mSyncedView.scrollTo(0, blah);
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
}
I think it is more appropriate to use a GridView with 2 columns, something like this:
<GridView
android:id="#+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="2"
/>
What I would like to do is to listen to the scrolling event for the left listview and then scroll the right listview by an proper offset. Below is my code, I tested it(very simple, just show you my thought) and you may add your code based on it.
package viewTest.example.hy;
import android.app.Activity;
import android.os.Bundle;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
public class ViewTestActivity extends Activity {
private ArrayAdapter<String> adapter0;
private ArrayAdapter<String> adapter1;
private String[] array0;
private String[] array1;
private ListView lv0;
private ListView lv1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
array0 = getResources().getStringArray(R.array.LV0);//letters from A to O
array1 = getResources().getStringArray(R.array.LV1);//numbers from 1 to 14
adapter0 = new ArrayAdapter<String>(this, R.layout.item, array0);
adapter1 = new ArrayAdapter<String>(this, R.layout.item, array1);
lv0 = (ListView) findViewById(R.id.listView1);
lv1 = (ListView) findViewById(R.id.listView2);
lv0.setAdapter(adapter0);
lv1.setAdapter(adapter1);
lv0.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
lv1.setSelection(firstVisibleItem);//force the right listview to scrollyou may have to do some calculation to sync the scrolling status of the two listview.
}
});
}
}
And this is the main.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="none">
</ListView>
<ListView
android:id="#+id/listView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="none" >
</ListView>
</LinearLayout>
Here is my screenshot:
I ended up using the top s/o answer here: Android. Scrolling 2 listviews together
Intercepting and redirecting events seems to be a lot more elegant and consistent than trying to do my own math on the dimensions and state of the listviews.
Related
so I am working on an app, using Android Studio, and I want to basically have 3 layouts. The first being a static background linear layout, that will only have a picture that is the background. Above that, is another Linear layout, that will have "nothing", and above that is an invisible grid layout, that each "box" has two numbers, rows, and columns, and Using that, I will know where to put stuff in my second Linear layout(E.g, If i want to move something to the top right, I will just put in the position 0,0 and it will put it on that position, but on the linear layout, rather than the grid layout.)
I already made the gridlayout, and the linear layouts, here is the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/map_backround"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/grassGreen"
android:gravity="center"
android:visibility="visible">
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
app:srcCompat="#drawable/greenBackround" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mapPosition">
<GridLayout
android:id="#+id/map_hardcore"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="4dp"
android:gravity="center"
android:horizontalSpacing="0dp"
android:numColumns="270"
android:stretchMode="columnWidth"
android:verticalSpacing="0dp"
android:visibility="invisible">
</GridLayout>
</LinearLayout>
</LinearLayout>
And The baseAdapter. Take in mind, class Map is basically a Class that inherits Coordination, and has a 2d array of coordinates (creating a 2d map of coordinates), And coordinates is just a class with 2 integers, one for rows and one for columns, giving me an id for each square.
public class gridViewHandler extends BaseAdapter
{
Context context;
private Map selectedMap;
private Coordination[][] position;
private int countLocations;
public gridViewHandler(Context context, Map selectedMap)
{
this.countLocations = 0;
this.context = context;
this.selectedMap = selectedMap;
this.position = selectedMap.getMapParams();
for(int i = 0; i < selectedMap.getColumns(); i++)
{
for(int a = 0; a < selectedMap.getRows(); a++)
{
countLocations++;
}
}
}
#Override
public int getCount()
{
return countLocations;
}
public int getColumnCount()
{
return position.length;
}
public int getRowCount()
{
return position[0].length;
}
public Object getItem(int colNum, int rowNum)
{
return position[colNum][rowNum];
}
#Override
public Object getItem(int i)
{
return null;
}
#Override
public long getItemId(int i)
{
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}
Lastly, Here is what my "Main_Activity" looks like(I called it game)
public class Game extends Activity {
private GridView defaultMap;
private Map map = new Map();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
defaultMap = (GridView) this.findViewById(R.id.map_hardcore);
gridViewHandler gridAdapter = new gridViewHandler(Game.this, map);
defaultMap.setAdapter(gridAdapter);
}
}
So, I don't really know how I can use what I already made. I think that the gridview is ready, and all I need to do is create the two linear layouts, then create the function where I insert the ID of the gridview box(rows,cols) and an item, and it will display it on the linear layout in that position. Any Idea how I can implement this?
My goal to achieve is a map where I will always be able to know, and control where every object is.
I'm building my first app based on material from http://javatechig.com/video/json-feed-reader-in-android.
Everything goes ok so far, but I found one bug with ListView elements, which I can not manage to resolve by myself :(
I have extended list_row_layout.xml by 2 fields:
<Button
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="komcie"
android:textSize="11sp"
android:id="#+id/loadComments"
android:layout_gravity="center|bottom"
android:background="#bbb"
android:layout_marginLeft="5dp"
android:enabled="true"
android:clickable="true"
android:onClick="clickedLoadComments"
android:elegantTextHeight="true"
android:layout_toRightOf="#id/thumbImage"
android:layout_below="#+id/content"
android:padding="1px" />
<ListView
android:id="#+id/comment_list"
android:layout_toRightOf="#id/thumbImage"
android:layout_below="#+id/content"
android:paddingTop="5dp"
android:layout_marginTop="0dp"
android:paddingLeft="5dp"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:cacheColorHint="#00000000"
android:dividerHeight="1dp"
android:focusable="false"
android:listSelector="#drawable/list_selector_flatcolor"
android:visibility="invisible" />
Button.android:onClick="clickedLoadComments" function load Json with elements into ListView/comment_list. It works quite fine. But if there are more elements than could be displayed on screen (~8 elements) there is a bug. Comments from clicked element are loaded into every 8th element in a ListView.
Some code:
public void clickedLoadComments(View v)
{
try {
View parent = (View)v.getParent();
ViewHolder t = (ViewHolder) parent.getTag();
if( parent != null ) {
this.loadCommentsForLeaf(parent);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
protected void loadCommentsForLeaf( View view )
{
String tmpUrl = "http://some.url.com/Ajax/LoadComments?lid=" + this.currentLeafInUse;
JSONObject commentsJson = this.getJSONFromUrl(tmpUrl);
this.parseJsonComments(commentsJson);
if( commentsJson != null )
this.updateCommentList(view);
}
public void updateCommentList( View view) {
commentListView = (ListView) view.findViewById(R.id.comment_list);
commentListView.setVisibility(View.VISIBLE);
CommentListAdapter cla = new CommentListAdapter(this, this.commentList.get(this.currentLeafInUse));
commentListView.setAdapter(cla);
// Set list height.
ViewGroup.LayoutParams params = commentListView.getLayoutParams();
params.height = setListViewHeightBasedOnItems(commentListView) + 20;
commentListView.setLayoutParams(params);
commentListView.requestLayout();
}
CustomListAdapter.java code is mostly the same as the one in tutorial.
I would really appreciate help as I have spent many hours figuring it out with not success :(
This is just a guess. You might post your Adapter code and your parseJsonComments also if this does not work.
The Cause:
The problem you are describing might be caused due to the recycling and the reusage of Views. Take a look at this image from http://android.amberfog.com
As you can see the 1. items is reused and becomes the 8. item after scrolling.
Let's assume that Item 1 has an OnClickListener which updates a Text of the item.
For example we set the text to "clicked" after the OnClickListener is triggered.
Because item 1 is reused to create item 8, item 8 will also display the text "clicked".
The Solution:
The usual way is to save all states/content in a List(or whatever) and update everything in the getView call. So if you want to update text:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
...
holder.textView.setText(jsonTexts[position]);
...
return convertView;
}
And if you want to update an item just update the List in your Adapter which holds the content/JsonObjects(etc.) and call notifyDataSetChanged.
public void updateCommentList(JSONObject commentsJson, int position) {
// does not exist you might create something
//like that in your Adapter class
commentListAdapter.updateItem(commentsJson,position);
commentListAdapter.notifyDataSetChanged();
}
After i populate the listview i call this method:
private void registerClickCallback() {
ListView list = (ListView) findViewById(R.id.lv);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long id) {
String xx = position+ ":" + id;
//then you can do what ever you want
}
});
}
Hey guys I have been trying to figure this out and have looked over a number of questions here but can't seem to find the answer to my problem. I am making an app that displays dinners at random from an array. I would like these dinners to be clickable and take the user to a web page but I have no idea how to make that happen so at the moment I have just added the link below the dinner which looks pretty ugly.
Here is the class that contains the recipes:
package me.oak.dinnertime;
import java.util.Random;
public class CookBook {
public String[] mfood =
{
"Chicago Deep Dish Pizza \n \n http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes",
"Spaghetti Bolognese \n \n http://www.bbcgoodfood.com/recipes/1502640/the-best-spaghetti-bolognese",
"Bourbon Chicken \n \n http://www.food.com/recipe/bourbon-chicken-45809",
};
public String getFood() {
String food = "";
//Randomly select a dinner
Random randomGenerator = new Random(); //Construct a new Random number generator
int randomNumber = randomGenerator.nextInt(mfood.length);
//Convert random number to text
food = mfood[randomNumber];
return food;
}
}
And here is the main activity:
package me.oak.dinnertime;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class DinnerTimeActivity extends Activity {
private CookBook mCookBook = new CookBook();
private ColourWheel mColourWheel = new ColourWheel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dinner_time);
final TextView dinnerLabel = (TextView) findViewById(R.id.DinnerTextView);
final Button showDinnerButton = (Button) findViewById(R.id.showDinnerButton);
final RelativeLayout relativelayout = (RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
String food = mCookBook.getFood();
//Update the label with the dinner
dinnerLabel.setText(food);
int colour = mColourWheel.getColour();
relativelayout.setBackgroundColor(colour);
showDinnerButton.setTextColor(colour);
}
};
showDinnerButton.setOnClickListener(listener);
}
}
And here is the XML file:
<RelativeLayout 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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".DinnerTimeActivity"
android:background="#ff51b46d"
android:id="#+id/relativeLayout">
<TextView android:text="What's for dinner?" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#80ffffff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/DinnerTextView"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textSize="24sp"
android:textColor="#android:color/white"
android:text="Click the button to find out!"
android:autoLink="web" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dinner Time"
android:id="#+id/showDinnerButton"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#android:color/white"
android:textColor="#ff51b46d" />
</RelativeLayout>
Sorry to give you so much, I just hope someone can help me out.
To use the LinkMovementMethod, try following:
change your array list content from:
Chicago Deep Dish Pizza \n \n http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes
to:
Chicago Deep Dish Pizza
And when set this text to your TextView, do it as:
(Updated: remove the underline and change text color, source: Remove underline from links in TextView - Android)
Spannable s = (Spannable) Html.fromHtml(foodString);
for (URLSpan u: s.getSpans(0, s.length(), URLSpan.class)) {
s.setSpan(new UnderlineSpan() {
public void updateDrawState(TextPaint tp) {
//remove the underline
tp.setUnderlineText(false);
//set text color
tp.setColor(getResources().getColor(R.color.orange));
}
}, s.getSpanStart(u), s.getSpanEnd(u), 0);
}
dinnerLabel.setText(s);
dinnerLabel.setMovementMethod(LinkMovementMethod.getInstance());
Also remove the
android:autoLink="web"
in the xml.
As I have tested, "Chicago Deep Dish Pizza" will appear as a clickable link in the testview.
just use something like this in your string file and refrence it in the textview
<string name="links">Google shalom is a boyGoogle 2 </string>
you can also use this in an array in the strings file
to make it actually work do this
terms = findViewById(R.id.terms);
terms.setMovementMethod(LinkMovementMethod.getInstance());
I answered this on Hackforums for you.
Store the links in a separate array make sure the indexes of the links line up with the location in the other array. So:
public class CookBook {
public String[] mfood =
{
"Chicago Deep Dish Pizza",
"Spaghetti Bolognese",
"Bourbon Chicken",
};
public String[] mLinks =
{
"http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes",
"http://www.bbcgoodfood.com/recipes/1502640/the-best-spaghetti-bolognese",
"http://www.food.com/recipe/bourbon-chicken-45809",
};
public int getRandomFoodIndex() {
//Randomly select a dinner
Random randomGenerator = new Random(); //Construct a new Random number generator
int randomNumber = randomGenerator.nextInt(mfood.length);
//Convert random number to text
return randomNumber;
}
public String getFood(int index) {
return mfood[index];
}
public String getLink(int index) {
return mLinks[index];
}
}
and then
public class DinnerTimeActivity extends Activity {
private CookBook mCookBook = new CookBook();
private ColourWheel mColourWheel = new ColourWheel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dinner_time);
final TextView dinnerLabel = (TextView) findViewById(R.id.DinnerTextView);
final Button showDinnerButton = (Button) findViewById(R.id.showDinnerButton);
final RelativeLayout relativelayout = (RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
int index = mCookBook.getRandomFoodIndex();
String food = mCookBook.getFood(index);
String link = mCookBook.getLink(index);
//Update the label with the dinner
dinnerLabel.setText(food);
/** open link with the link variable */
int colour = mColourWheel.getColour();
relativelayout.setBackgroundColor(colour);
showDinnerButton.setTextColor(colour);
}
};
showDinnerButton.setOnClickListener(listener);
}
}
I need to create Collapse / Expand forms in Android. I am thinking about using either RelativeLayout or TableLayout for this purpose. But, what XML element make these forms expand and hide in android?
If you are not sure what I am not talking about, take an application like Sales Force for an example. There you have these expandable menus in all the forms. How can I do this?
Following is an example (taken from Sales Force)
When you expand these, it looks like below
You could do the following. create a layout that has the following:
1. A Heading or a textview with the label contacts
2. Below it a layout that has forms related to it
3. Add another textview below #2 and name it address
4. Add a lyout below #3 .
The layout 2 and 4 will have visibility gone in the first case
When the user taps on layout 1, or the first textview, make layout 2 visible and vice versa. Do the same with the second textview.
Hope that helps.!
I have had a similar problem, i want parts of my form to be hidden in sektions and created a class for this issue.
public class section extends LinearLayout{
public LinearLayout container;
public Button toggler;
public section(Context context, String section_name, String section_state) {
super(context);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.flxsection, this);
container = (LinearLayout) this.findViewById(R.id.container);
container.setVisibility(section_state.equals("0") ? View.GONE:View.VISIBLE);
toggler = ((Button)this.findViewById(R.id.section_toggle));
toggler.setTag(section_state);
toggler.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String tag = (String) v.getTag();
v.setTag(tag.equals("0") ? "1":"0");
if(tag.equals("0")){expand(container,false);}else{collapse(container,false);}
setImage(tag.equals("0"));
}
});
toggler.setText(" " + section_name);
setImage(section_state.equals("1"));
setTextSize();
}
public void setTextSize(){
toggler.setTextSize(GV.Style.TextSize);
}
public void setImage(boolean open){
int a = open ? R.drawable.minus_48_white: R.drawable.plus_48_white;
Drawable img = main.res.getDrawable(a);
final float scale = main.res.getDisplayMetrics().density;
int size = (int) (12 * scale + 0.5f);
img.setBounds(0,0,size,size);
toggler.setCompoundDrawables(img,null,null,null);
}
}
the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:focusable="false"
android:layout_marginLeft="4dip"
android:layout_marginRight="4dip"
android:orientation="vertical" >
<Button
android:id="#+id/section_toggle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dip"
android:layout_marginTop="4dip"
android:background="#drawable/section"
android:drawableLeft="#drawable/plus_48"
android:focusable="false"
android:gravity="left|center_vertical"
android:padding="6dip"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:textSize="22dip" />
<LinearLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
Expand and collapse:
public static void expand(final View v,boolean quick) {
v.requestLayout();
v.measure(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
final int targtetHeight = v.getMeasuredHeight();
v.getLayoutParams().height = 0;
v.getLayoutParams().width = LayoutParams.FILL_PARENT;
v.setVisibility(View.VISIBLE);
if(quick){
v.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targtetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
//(int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density)
v.startAnimation(a);
}
}
public static void collapse(final View v,boolean quick) {
v.requestLayout();
final int initialHeight = v.getMeasuredHeight();
if(quick){
v.setVisibility(View.GONE);
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)( initialHeight/ v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
v.startAnimation(a);
}
}
If if create a form and need a section, i create a instance of this class and add the controls.
You might need to turn the hardware acceleration on in order to get the best performance
edit:
Usage is like:
section s = new section(context, section_name, section_state);
s.container.addView([your view 1]);
s.container.addView([your view 2]);
s.container.addView([your view 3]);
//...
form.addView(s);
I have an activity with a list of Products (like a shopping list), in which we can choose the number of product units.
The activity contains EditText with TextWatcher and a ListView with a personal Adapter (extends BaseAdapter).
When I type a key in the EditText, the listView of products is refreshed with the new data.
But I would like to keep the state of my selected data.
For example, I type a reference in the EditText, then the listView contains 3 datas (A, B, C), I choose A, and type 5 units of it, then I type a new reference in the EditText (A and B disappears).
The listView contain only C, but I remove my search and go back to A, B, C.
the problem, the product A is unselected and have 0 of units (the 5 units have disappeared).
I would like to keep the selected products and the units even if I change my search in the EditText.
How to do that please ?
Here is a code snippet :
The layout of the activity :
<?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" >
<EditText
android:id="#+building_list/search_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Filter by reference"
android:inputType="textAutoCorrect|none|textAutoComplete|none|textNoSuggestions"
android:maxLines="1"
android:textSize="20dp" />
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="10dp"
android:id="#+id/productListView">
</ListView>
</LinearLayout>
The Adapter :
public class AdapterProduct extends BaseAdapter {
private List<Product> lstProduct;
private LayoutInflater mInflater;
public AdapterProduct(Context context, List<Product> listP) {
lstProduct = listP;
mInflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {
CheckedLinearLayout layoutItem;
if (convertView == null) {
layoutItem = (CheckedLinearLayout) mInflater.inflate(R.layout.row_product, parent, false);
final ViewHolderProduct viewHolder;
viewHolder = new ViewHolderProduct();
viewHolder.btPlusAmount = (Button)layoutItem.findViewById(R.id.btPlusAmount);
viewHolder.btPlusAmount.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Product p = (Product) viewHolder.product.getTag();
p.setAmount(p.getAmount()+1);
notifyDataSetChanged();
}
});
}
else {
layoutItem = (CheckedLinearLayout) convertView;
((ViewHolderProduct) layoutItem.getTag()).btPlusAmount.setTag(lstProduct.get(position));
}
ViewHolderProduct viewHolder = (ViewHolderProduct) layoutItem.getTag();
viewHolder.amount.setText(String.valueOf(lstProduct.get(position).getAmount()));
}
static class ViewHolderProduct {
protected TextView amount;
protected Button btPlusAmount;
}
}
And the AsyncTask with TextWatcher :
AsyncTask
doInBackground =>
modelProduct = new AdapterProduct(leContext,
ProductJSON.getService().searchProducts(leContext, url, params[0])); //params[0] = the text of EditText
private TextWatcher filterTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
//AsyncTask task
task.execute(s.toString());
}
};
I let you check my answer here.
1) Basically, add a new attribute to your adapter. A simple int[] is enough. Store the number of products selected inside.
2) Each time you build the View of a row of your ListView, check the number of products selected.
3)Make sure to update the number of products selected when you click on the button. Also, make sure to resize/update this array when your List changes. Call notifyDataSetChanged() Each Time you click on a product.