I have a ListView, and I have to implement specific behaviour for it.
When user scrolls up the ListView , which is in initial position:
ListView should move down a bit;
ProgressBar should appear;
Next image shows the result that I want to achieve:
Any suggestions how to do this? Thanks.
Use SwipeRefreshLayout from support-v4 https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html
Wrap the ListView in a SwipeRefreshLayout in xml:
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
And set the listener in your onCreate():
SwipeRefreshLayout swipe = (SwipeRefreshLayout) findViewById(R.id.swipe);
swipe.setOnRefreshListener(this);
and implement it
#Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override public void run() {
swipe.setRefreshing(false);
}
}, 5000);
}
"There's a library for that"
another library
I believe this library does what you're looking for.
I got this picture from this question
There are lots of libraries doing similar things like in this video https://www.youtube.com/watch?v=YOYtPF-4RPg
You can use SwipeRefreshLayout or other library as suggested in #Cobbles answer.
It is not exactly the view you looking for, but the same feature. The advantage of swipe refresh layout is that is part of android support library and user are used to see it.
Related
RealmRecyclerView i want to load more data on swipe top instead of bottom how to set RealmRecyclerView default load more on top.
If you want to load more data by swiping up in RecyclerView, I think, SwipeRefreshLayout is the good option. It is very easy to implement and also give efficient callback on swipe with loader. Please refer following code as a reference:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never" />
</android.support.v4.widget.SwipeRefreshLayout>
Callback Method:
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Refresh items
}
});
Hope this will help you.
I have experienced strange behaviour with smooth scroll on listview.
I have 30 items in list. When I smooth scroll via
listview.smoothScrollToPositionFromTop(29, 0);
there will be some extra space at the end of screen. Actually listview shifts up a little. Image attached below. But if I scroll manually there will be no space. What can be done to resolve this behaviour?
Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_orange_light">
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
As you have said, I think it's an Android issue. It appears to be part of the animation for over scroll, it seems to get 'stuck' before completing the animation. I've had similar experience with SwipeToRefresh, where the progress indicator doesn't fully disappear after refresh.
Anyway, you can workaround by turning off the animation
listView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Unfortunately, this loses the animation even if manually scrolled. If you can live with that, I think this will fix your problem.
AbsListView#setOverScrollMode(int)
EDIT: (after original answer was accepted)
I have also found another work around. This one preserves the over scroll animation. Unfortunately, it has another drawback. If the user auto scrolls before doing anything else, the same problem of the border at the bottom exists. If the user manually scrolls to the bottom 1st, no problem from then on. If the user auto scrolls and gets the border, then manually scrolls, no more problem. So, here is the alternate method.
Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.invisible_footer, null);
listView.setOverscrollFooter(drawable);
In the drawable folder, "invisible_footer.xml"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="2dp"
android:width="10dp"
android:viewportWidth="10"
android:viewportHeight="2">
<!-- a horizontal line -->
<path android:pathData="M 1 1 H 10"
android:strokeColor="#00000000" android:strokeWidth="1" />
</vector>
ListView.html#setOverscrollHeader()
This gives choices:
Lose over scroll animation
Retain animation but risk user seeing bottom border 1 time
Did you try to set the height of your ListView to wrap_content instead of match_parent?
Even in [this tutorial] all the attributes are set to wrap_content. So replace your ListView attributes on width and height to:
<ListView
android:id="#+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
i have implemented. but, at initial first time it keep the padding at bottom but, from second time its working fine.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.socialintegration.ListAct">
<ListView
android:id="#+id/listTemp"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>
CODE :
public class ListAct extends AppCompatActivity {
ListView l;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
String str[] = new String[50];
for (int i = 0; i < 50; i++) {
str[i] = "poistion" + i;
}
ArrayAdapter adpt = new ArrayAdapter(ListAct.this, android.R.layout.simple_dropdown_item_1line, str);
l = (ListView) findViewById(R.id.listTemp);
l.setAdapter(adpt);
l.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
l.smoothScrollToPositionFromTop(29, 0);
}
});
}
}
There is an other SO post link which describes a similar problem. I guess the solution in that post should solve your problem.
try this to your xml:
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:clipToPadding="false"/>
<ListView>
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior/>
Ok so try:
app:layout_behavior="#string/appbar_scrolling_view_behavior"
I strongly believe to move to RecyclerView.
If you don't want to move.
Here is work around. Just add this method to your activity, and call it.
private void smoothScrollToTop(final int pos) {
listView.smoothScrollToPositionFromTop(pos, 0);
listView.post(new Runnable() {
#Override
public void run() {
listView.smoothScrollToPosition(pos);
}
});
}
This is well tested. and worked for me. And here is output.
I have a listview for my android app and I want to make an animation at the top of the list view when the user over scrolls like one the one for the instagram or twitter app. How would I go about this. Is there a method that is called when the user over scrolls and I was thinking about using a frameanimation for the actually animation.
You can add a swipe refresh layout on your xml file:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/favs_refresher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<ListView
android:id="#+id/favs_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
</android.support.v4.widget.SwipeRefreshLayout>
Then on your activity:
swipeRefresher = (SwipeRefreshLayout)findViewById(R.id.favs_refresher);
swipeRefresher.setOnRefreshListener(this);
Be sure that your activity implements SwipeRefreshLayout.OnRefreshListener
then you can make use of the onRefresh() method:
#Override
public void onRefresh() {
//do something
}
I'm trying to remove a progress indicator after loading my data in a fragment involving a ListView. Here is my completion handler:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
dataSource = (ArrayList<Map<String, Object>>) task.getResult();
PostAdapter adapter = new PostAdapter(getActivity(), dataSource);
ListView list = (ListView) rootView.findViewById(R.id.listView);
list.setAdapter(adapter);
View indicator = getActivity().findViewById(R.id.indicator);
RelativeLayout layout = (RelativeLayout) getActivity().findViewById(R.id.layout);
layout.removeView(indicator);
}
});
The last 3 lines of code is the relevant part. Everything is called correctly, nothing is null etc. in debug everything works perfectly. The adapter also works correctly, populating my list, but the indicator is still on the screen. I've also tried setting it's visibility to GONE or HIDDEN but they also don't seem to hide it either. I've seen Android - Can't hide progress bar but it's answers involve setEmptyView() which I'm not using anyway. I am using the same fragment (of course, a different instance) in another tab, and it works correctly.
Here is my layout 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:padding="0dp"
android:background="#ffffffff"
android:id="#+id/layout">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listView"
android:layout_margin="0dp"
android:padding="0dp" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/indicator"
android:indeterminate="true"
android:layout_centerInParent="true" />
</RelativeLayout>
What am I doing wrong?
I've found out the problem (thanks to all the commenters). I was calling activity's methods to find and remove the view. The problem is that, I have multiple instances of the same fragment in the same activity, under different tabs. I've used my fragment's root view to find and remove the indicator, instead of the activity, and it worked.
Change the codes of last three lines in onClick(...) as:
View indicator = (ProgressBar)rootView.findViewById(R.id.indicator);
and use:
indicator.setVisibility(ProgressBar.GONE);
or codes:
RelativeLayout layout = (RelativeLayout) rootView.findViewById(R.id.layout);
layout.removeView(indicator);
I'm using a ListView as a secondary view in my SlidingPaneLayout.The main view is a map fragment. The ListView acts as a menu. The problem is that onItemClickedListener never gets called on the ListView. Even the list row never gets highlighted on press. it seems that the ListView can't get the focus.
EDIT:
actually, slidingPaneLayout.findFocus() shows that android.widget.ListView. still no luck on clicking the list items.
Here is my xml
<com.ziz.luke.custom_components.MySlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/slidingpanelayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/contactsList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00000000" >
</ListView>
<TextView
android:id="#+id/android:empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal|center_vertical"
android:text="#string/noContacts" />
</RelativeLayout>
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</com.ziz.luke.custom_components.MySlidingPaneLayout>
How can I solve this??
I've found the answer. I was using a subclass of SlidingPaneLayout in which I was overriding
onInterceptTouchEvent(MotionEvent arg0)
I was trying to do the following:
open the slidingPaneLayout useing a button.
close the slidingPaneLayout useing a button.
close the slidingPaneLayout useing swiping.
prevent the user from opening the slidingPaneLayout using swiping.
So, I created a boolean inside my subclass called shouldSwipe to be returned from the over-ridden method.
the implementation that caused the problem was :
#Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
return shouldSwipe;
}
it caused the problem whenever (shouldSwipe = true) because it tells the system that the touch event already is consumed and prevents it from being propagated.
I solved that using this one:
#Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
// TODO Auto-generated method stub
return shouldSwipe ?super.onInterceptTouchEvent(arg0):shouldSwipe;
}
that's it.
Just a suggestion but maybe using the NavigationDrawer for a Navigation List Drawer would be easier then reinventing the wheel.
http://developer.android.com/design/patterns/navigation-drawer.html
I have just created an example project using SlidingPaneLayout.
I didn't use any map because there is not where the problem is, so I just refer the position of the map with a TextView. I did use a ListFragment that is working and receiving the click listeners. Please download the project from here:
https://dl.dropboxusercontent.com/u/33565803/StackOverFlowExamples/SlidingPaneLayoutExample.zip
Let me know if you have any configuration problem and if it solves your problem ;)
(I am using actionBarSherlock just because I am used to, so you can remove it if you want)
Try using this powerful library to make a simple sliding bar :
https://github.com/jfeinstein10/SlidingMenu
and here is how you can import it and use it :
Solved: how to import SlidingMenu on my project with ActionBarSherlock 4.2.0