Scrolling with two ListViews, trying to populate a LinearLayout instead - android

got myself into a pickle trying to squeeze two ListViews in the same activity. It works, using two separate ListFragments contained in a standard (vertical) LinearLayout.
The problem is, the two lists together are longer than the screen and the second list is therefore partially hidden. Visually, the user expects to drag the whole screen up and unveil the second list. But the two lists have their own internal scrolling and they do not allow for the whole screen to scroll as one piece.
Luckily the lists actually contain very few items (5 each on average). So, theoretically, I could populate a couple of LinearLayouts containers instead. The problem is, the data being displayed by the lists comes from a Cursor and is dynamic. While I am aware of the newView() and bindView() methods of the CursorAdapter, I don't quite understand how I can connect the adapter to the LinearLayout containers instead of ListViews. I.e. how does the CursorAdapter know that it must create 5 row items out of the 5 items it finds in its cursor? Where do I create the loop that iterates over the cursor item and creates the items in the LinearLayout container? And how do I refresh the content of the LinearLayout when the data in the Cursor changes? All the examples I'm finding neatly wrap these issues into the ListView provided by the ListActivity, but I can't use ListViews!
I'm confused!
Manu
EDIT : Here is the xml layout of the (Fragment)Activity when following breceivemail suggestion. Commented out is the original LinearLayout container, prior to breceivemail's suggestion. It should also be noted the the whole activity is in turn contained by a TabHost, but I don't know if that make any difference for the problem at hand.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!--
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
-->
<TextView android:id="#+id/title"
android:textSize="36sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/SelectPlayer"/>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/Playing"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#000000"
android:background="#999999"/>
<fragment android:name="com.myDomain.myApp.PlayerListFragment"
android:id="#+id/playing"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/Reserve"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#000000"
android:background="#999999"/>
<fragment android:name="com.myDomain.myApp.PlayerListFragment"
android:id="#+id/reserve"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

Put your listViews in a vertical scroll. You can have scrollable listView inside of a vertical scroll by the following trick. use the following code and enjoy!
private int listViewTouchAction;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
setListViewScrollable(myListView1);
setListViewScrollable(myListView2);
}
private void setListViewScrollable(final ListView list) {
list.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
listViewTouchAction = event.getAction();
if (listViewTouchAction == MotionEvent.ACTION_MOVE)
{
list.scrollBy(0, 1);
}
return false;
}
});
list.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE)
{
list.scrollBy(0, -1);
}
}
});
}
listViewTouchAction is a global integer value.

Related

How to disable scrolling in HorizontalScrollView?

What i want in pictures:
On the words: i want to disable scrolling with formatting text inside HorizontalScrollView.
Part of XML:
<ScrollView
android:id="#+id/review_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="horizontal"
android:fillViewport="true"
android:layout_marginTop="10dp">
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tt_review_content"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Some long text"
android:scrollHorizontally="true"/>
</HorizontalScrollView>
</ScrollView>
Method(doesn't works):
private void setTtAreaWrapContent(boolean value) {
ViewGroup.LayoutParams params = textField.getLayoutParams();
if(value) { // Wrap content
textField.setWidth(scrollView.getWidth());
} else { // Scroll
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
textField.setLayoutParams(params);
}
There is a very simple way to do this.
Check if the user wants to scroll or not and then store it in a boolean variable, shouldScroll.
Now do this in onCreate,
HorziontalScrollView scrollView= (HorizontalScrollView)findViewById(R.id.scrollView);
if(!shouldScroll)
scrollView.setOnTouchListener(new OnTouch());
You also need to define a class OnTouch extending the OnTouchListener
private class OnTouch implements OnTouchListener
{
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
}
Now for the TextView formatting, just use android:singleLine="false" or use android:width="0dip"
I had absolutely the same need for code, so I initially proposed a ViewSwitcher with the same layouts, but one with HorizontalScrollView and one without it. And switch to the corresponding view depending on the setting.
However, I found an easier solution. After recreation of the Activity (when wrapping settings are changed by the user), use the code in the onCreate methode:
if (isWrapContent)
{
View mTV = findViewById(R.id.my_text_view);
HorizontalScrollView myHSV = (HorizontalScrollView) findViewById(R.id.my_hsv);
ViewGroup parent = (ViewGroup) myHSV.getParent();
ViewGroup.LayoutParams params = myHSV.getLayoutParams();
int index = parent.indexOfChild(myHSV);
myHSV.removeAllViews();
parent.removeView(myHSV);
parent.addView(mTV, index, params);
}
You need to use your id's and variables correspondingly.
It will remove the horizontal scrollview with the embedded textview and then reinsert the textview.
My answer provides direct and valid answer on how the asked issue could be resolved instead of freezing the horizontal scrollview or wondering about the point of the question, as it is done in the other comments and answers.

3 way scroll in Android

I have 3 views: an ImageView, a RelativeLayout and a ListView. When the user scrolls down, I have to hide the ImageView first. When the top of the RelativeLayout touches the top of the screen it has to fix itself there and the scroll must be done by the ListView. Then when I scroll up, the top of the ListView must be visible before the ImageView starts to scroll down again.
Is there any component that does what I want without having to write my own component?
(Just to make things easier, it should work like the headers in Instagram, when the header reaches the top it stays there, but there should be only one header)
I have a very simple solution to this, hope it helps. I use one header added to the listView and the same header added to the page on top. There is a listener to toggle visibility of the fixed header. Everything is done in the onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.list);
LayoutInflater inflater = getLayoutInflater();
// your image header
View headerImage = inflater.inflate(R.layout.header_image, listView, false);
listView.addHeaderView(headerImage);
// the header that scrolls with the listview
final View fixedHeader = inflater.inflate(R.layout.header_fixed, listView, false);
listView.addHeaderView(fixedHeader);
// the header that is fixed on top of the screen
final View secondFixedHeader = findViewById(R.id.fixed_header);
secondFixedHeader.setVisibility(View.GONE);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > 0) {
secondFixedHeader.setVisibility(View.VISIBLE);
} else {
secondFixedHeader.setVisibility(View.GONE);
}
}
});
listView.setAdapter(new ListAdapter(this));
}
there is the activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="#+id/fixed_header"
layout="#layout/header_fixed" />
</RelativeLayout>
there is the header_fixed.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="#android:color/darker_gray">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a fixed header"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large"/>
</RelativeLayout>
and there is the header_image.xml:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/android"/>

How to prevent flickering ListView when requesting Layout very often

I'm implementing a "parallax" effect which consists of a list view and an image view above.
When the user scrolls downwards, the offset is subtracted from the height of the image view. This works fine. I'm doing this in the scroll listener of the list view. To really update the listview and imageview in realtime I need to call requestLayout().
The problem is, that this method is asynchronous and if I scroll slowly it flickers extremely. If I just swipe quickly it looks very nice. Is there an other solution to solve this?
ScrollListener
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View c = view.getChildAt(0);
int top = (c == null) ? 0 : (-c.getTop() + view.getFirstVisiblePosition() * c.getHeight());
//Log.d(TAG, "Offset = " + top);
mImageView.getLayoutParams().height = 400 - top;
mImageView.requestLayout();
}
Layout
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="xxx.fragments.NewsFragment">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#android:color/holo_blue_light"
android:id="#+id/advertisement"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/news_feed">
</ListView>
</TableLayout>
If you just want the ImageView to scroll with the list, then you can simply add it as a header view:
listView.addHeaderView(mImageView);
Make sure you call this method before calling setAdapter. Also make sure your ImageView doesn't already have a parent, so inflate it separately or just create one in code using new ImageView.

Add a footer to a GridView Android

I am developing an android application for listing the products of an on-line store. For this I have used a GridView for that. But inside a category could be a big number of products, so I have to implement a feature like, "Loading on demand", with a button at the end of a gridView telling (Load More). Of course this button will be visible only if the GridView has reached the end of the items. But I dont how to do it. Below is my solution so far, but the button is not visible when gridview goes at the end.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<com.twotoasters.jazzylistview.JazzyGridView
android:id="#+id/ebuy_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:drawSelectorOnTop="true"
android:horizontalSpacing="15dp"
android:numColumns="2"
android:verticalSpacing="15dp" />
<TextView
android:id="#+id/more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/ebuy_now_background"
android:clickable="true"
android:onClick="loadMore"
android:padding="15dp"
android:text="Load More"
android:textColor="#color/ebuy_color_second_strip"
android:textSize="25sp" />
</LinearLayout>
</ScrollView>
Suggestions or other solution will be more than welcome :)
as you implement and add this listener to your Gridview this will detect for the end of Gridview as scroll position was at end of list just get more data. And during the loading data you need one flag to load data at once when the scroll position goes to end. So if data is loading and during that time you scroll up then scroll down then it will not get more data for dupplication.
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.currentFirstVisibleItem = firstVisibleItem;
this.currentVisibleItemCount = visibleItemCount;
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.currentScrollState = scrollState;
this.isScrollCompleted();
}
private void isScrollCompleted() {
if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
/*** In this way I detect if there's been a scroll which has completed ***/
/*** do the work for load more date! ***/
if(!isLoading){
isLoading = true;
loadMoreDAta();
}
}
}
Make "Load More" button part of the GridView - in your getView method inflate a layout with button when "position" corresponds to last item.

Passing from a listview to a gridview

I have an activity with a list, whose items are made of an image+text. I need to allow the user to change the view and have a gridview instead of it (whose elements are still made of the same image+text).
The user can do it through an icon menu:
public boolean onOptionsItemSelected(MenuItem item)
{
if(item.getItemId()== R.id.change_view)
{
// ?
}
}
I tried to just set the new adapter(see below) but it doesn't work..do I have to create a new activity to do that?
if(item.getItemId()== R.id.change_view)
{
setContentView(R.layout.grid_view);
gridViewAdapter = new GridViewAdapter(this,R.layout.bookmark_list_item,MyApp.getItems().findAll());
list.setAdapter(gridViewAdapter);
list.setVisibility(View.VISIBLE);
}
There are several ways you could achieve that.
One solution is to have both the ListView and GridView stacked in a FrameLayout, and when you want to switch between these views, set the visibility GONE to one view and VISIBLE to another, then viceversa.
Put both the ListView and GridView in a ViewFlipper
Or, use a ViewSwitcher
And finally, use just a GridView, but when you want to transition to a list view, set programmatically the number of columns to 1.
I finally resolved with something like this:
For the layout of my activity i have:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ViewStub android:id="#+id/list"
android:inflatedId="#+id/showlayout"
android:layout="#layout/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
<ViewStub android:id="#+id/grid"
android:inflatedId="#+id/showlayout"
android:layout="#layout/grid_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
</merge>
then i've defined the layout for the list and the grid (and also for their items), and managed the passage between them inflating the layouts and then by this method:
private void changeView() {
//if the current view is the listview, passes to gridview
if(list_visibile) {
listview.setVisibility(View.GONE);
gridview.setVisibility(View.VISIBLE);
list_visibile = false;
setAdapters();
}
else {
gridview.setVisibility(View.GONE);
listview.setVisibility(View.VISIBLE);
list_visibile = true;
setAdapters();
}
}
the complete code is available in this article: http://pillsfromtheweb.blogspot.it/2014/12/android-passare-da-listview-gridview.html

Categories

Resources