I have a searchview and recyclerview , I share the xml code
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="#+id/searchinput"
android:layout_width="match_parent"
android:background="#FFFFFF"
android:searchIcon="#null"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/searchinput"
android:layout_alignParentStart="true" />
</RelativeLayout>
Now I make request to web onQueryTextSubmit(String query), I call a function in my adapter class where I do the following
public void filterData(String query){
query=query.toLowerCase();
if(query.isEmpty()){
images.clear();
images.addAll(orignallist);
notifyDataSetChanged();
}
else {
// This is main function
getimages(query);
}
}
I here get images url in a separate thread from the web through jsoup and show it in the recycler view through piccaso, it works perfectly but it only shows when I scroll down a bit , I use this with piccaso in onbindviewholder()
Picasso.get().load(images.get(position)).fit().networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE).centerInside().into(holder.imageView);
How to show image without scrolling , thank you!
When search button clicked , when scrolled down a bit
Update : after adding more functions it is now showing only when the keypad pops up
Problem was that I was trying to use notifydatasetchanged() inside thread , so I passed activity to the adapter and implemented this :
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
Images where showing on scrolling or keypad opening because adapter items were getting recycled
Related
I am creating a simple view where on the top I have some elements and below a recyclerView. When I scroll it down, would like to scroll the whole screen, not the only recycler.
I have achieved it with NestedScrollView, however, now the problem appears. Items in the list will be pretty heavy and in this configuration, all the items are bind at the same time(call of onBindViewHolder).
any ideas how to make them recycle and solve this problem?
Here is my xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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="#android:color/darker_gray"
android:orientation="vertical"
tools:context="com.gkuziel.testkotlin.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_available_stores_default" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test text" />
<android.support.v7.widget.RecyclerView
android:id="#+id/list_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="false"
android:nestedScrollingEnabled="false">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Update:
The found a sweet solution: you add a complex header as ItemDecoration, its great cause your adapter can stay untouched, you just add sth like this:
recyclerView.addItemDecoration(dividerItemDecoration);
the only drawback of this solution is i couldn't make this header clickable (in my case it contains another recyclerView), however I know some people achieved it as well.
For this moment I decided implement heterogeneous recyclerview, with 1 instance of header type and the rest of simple row types.
What is important, the header type is fully binded once in HeaderViewHolder constructor and onBindViewHolder looks like this:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is HeaderViewHolder) {
//do nothing
Log.d("ProductAdapter", "Binding: Header")
} else if (holder is ItemViewHolder) {
Log.d("ProductAdapter", "Binding: " + position.toString())
val searchItem = items!![position - 1]
//here the proper binding is going on
}
}
You can try setting the recyclerview layout manager's method canScrollVertical to false and it won't respond to any touch inner scroll events.
override below method and return false.
boolean canScrollVertically()
here it is how to set.
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Lookup the recyclerview in activity layout
RecyclerView listTest = (RecyclerView) findViewById(R.id.list_test);
// Attach the adapter to the recyclerview to populate items
listTest.setAdapter(adapter);
// Set layout manager to position the items
listTest.setLayoutManager(new LinearLayoutManager(this){
#Override
public boolean canScrollVertically(){
return false;
}
});
// That's all!
}
I use the following Code in my RecyclerView.Adapter to remove an Item. If the current scroll-position is at the top, everything works fine.
If the scroll-position is somewhere in the middle of the List, the List automatically scrolls to the Top of the View.
How to avoid this behaviour?
public class MyAdapter extends RecyclerView.Adapter {
...
public void removeItem(int pos){
mDataset.remove(pos); //List with Items
notifyItemRemoved(pos);
notifyItemRangeChanged(pos,mDataset.size());
}
}
<FrameLayout
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">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
...
</FrameLayout>
Adding the following Line solved it for me
recyclerView.setHasFixedSize(true);
for recycler view you use
yourRecylerView.scrollToPosition(position);
Just check whether this position is present in the list.
Use this :
mDataset.remove(pos);
adapter.notifyItemRemoved(pos);
adapter.notifyDataSetChanged();
You need to scroll to the position removed after notifying the dataset associated with the RecyclerView is changed.
And yes, you just have to call notifyDataSetChanged() after removing an item from the mDataset. So your adapter will look like this.
public class MyAdapter extends RecyclerView.Adapter {
//... Code goes here
public void removeItem(int pos){
mDataset.remove(pos);
notifyDataSetChanged();
recyclerView.scrollToPosition(pos - 1);
}
}
Try this
mDataset.remove(pos);
adapter.notifyItemRemoved(pos);
adapter.notifyDataSetChanged();
This should work.
Try this code:
public void removeItem(int position){
mdata.remove(position);
notifyItemRangeChanged(position,mdata.size());
}
I use recyclerView inside nestedScrollView and had the same issue. Here is the code to call to remove an item
mDataset.remove(pos) // Remove from dataset
notifyItemRemoved(pos) // Show animation of removing
And here are lines to be added to XML to make it scroll correctly (RecyclerView is focused with higher priority than its viewHolders so it won't scroll)
android:descendantFocusability="beforeDescendants"
android:nestedScrollingEnabled="false"
After that everything was ok.
I use android.support.v4.widget.SwipeRefreshLayout in my Android app. It wraps a ListView. The content of the list view is downloaded from a server.
A progress view is shown when user swipes down in order to reload data from server. The progress view looks like a piece of circle that grows and shrinks during the animation. It seems that the style of this progress view cannot be customized much. However, I am fine with its built-in style.
I also show the same progress animation during initial data loading. This can be achieved by calling mySwipeRefreshLayout.setRefreshing(true). That's perfectly OK too.
However, I would like to show the same progress indication through the whole app. Consider e.g. another activity that looks like a form with submit button. There is neither a ListView nor a SwipeRefreshLayout in this form activity. Some progress indication should be displayed while the submitted data are transferred to the server. I want to show a progress bar with the same animation like in SwipeRefreshLayout.
Is there a simple and clean way to have the same progress indicator for both a SwipeRefreshLayout and a form activity that does not contain any list view and refresh layout and does not support any swipe gesture?
Thanks.
However, I would like to show the same progress indication through the
whole app. Consider e.g. another activity that looks like a form with
submit button. There is neither a ListView nor a SwipeRefreshLayout in
this form activity. Some progress indication should be displayed while
the submitted data are transferred to the server. I want to show a
progress bar with the same animation like in SwipeRefreshLayout.
yes you can use SwipeRefreshLayout to show like ProgressDialog when button click. check below.
i have added SwipeRefreshLayout inside my layout file still there is not ListView or ScrollView. just like below
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="niu.com.djandroid.jdroid.androidstack.MainActivity"
tools:showIn="#layout/activity_main">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/activity_main_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<SeekBar
android:id="#+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="54dp" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
now in my activity i used AsyncTask to show SwipeRefreshLayout. also use mSwipeRefreshLayout.setOnRefreshListener(null) to stop swipe gesture.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.activity_main_swipe_refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(null);
((Button) findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// mSwipeRefreshLayout.setRefreshing(true);
// call AsyncTask
new LongOperation().execute("");
}
});
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
// stop mSwipeRefreshLayout
mSwipeRefreshLayout.setRefreshing(false);
}
#Override
protected void onPreExecute() {
// start mSwipeRefreshLayout
mSwipeRefreshLayout.setRefreshing(true);
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
EDITED:15/02/20
After 4 year, Here is great explanation on android developer site
mSwipeRefreshLayout.setOnRefreshListener(null)
didn't work for me, so I made this method to enable and disable refreshing.
private void setToRefresh(boolean refresh) {
if (refresh) {
mSwipeRefreshLayout.setEnabled(true);
mSwipeRefreshLayout.setRefreshing(true);
} else {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.setEnabled(false);
}
}
I'm using Chris Bane's "deprecated" Pull-to-Refresh library. Everything's working nicely. What I'm able to do:
1.) When there's content in the listview I can do a pull to refresh. I can see the progress dialog spinning and everything.
2.) On first load of the app if there's no data/empty listview, I can show the empty textview and I am able to do the same pull to refresh with the spinning progress bar showing.
But the second time I go to this listview (that's inside a Fragment), with empty data nothing happens. Can't do a pull to refresh -- the progress dialog doesn't show, doesn't even pull the layout. It just shows an empty text (that you can't pull anymore).
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/ptr_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.handmark.pulltorefresh.library.PullToRefreshListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:divider="#19000000"
android:dividerHeight="1dp"
android:fadingEdge="none"
android:fastScrollEnabled="false"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:descendantFocusability="blocksDescendants"
app:ptrDrawable="#drawable/ic_logo_blue"
app:ptrRotateDrawableWhilePulling="false"
app:ptrScrollingWhileRefreshingEnabled="false"
app:ptrHeaderBackground="#EEEEEE"
app:ptrRefreshableViewBackground="#F7F7F7"
android:smoothScrollbar="true" />
<TextView
android:id="#+id/emptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:text="Empty list"
android:gravity="center"
android:visibility="gone"/>
I also tried replacing the RelativeLayout with LinearLayout, but the issue still exists.
Additional Info
Not sure if these are relevant:
The Fragment that contains the listview is inside a SlidingTab
The listview reference to the pull to refresh listview has a height of 0.
Here's the code to the Fragment's onCreateView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
result = (RelativeLayout)inflater.inflate(R.layout.listview, container, false);
listView = (PullToRefreshListView)result.findViewById(R.id.directoryList);
emptyTextView = (TextView)result.findViewById(R.id.emptyEventsView);
adapter = new ListViewAdapter(getActivity(), R.layout.listview_item, someList);
listView.setAdapter(adapter);
listView.setEmptyView(emptyTextView);
listView.setOnItemClickListener(this);
listView.setOnRefreshListener(this);
listView.post(new Runnable() {
#Override
public void run() {
listView.setRefreshing();
}
});
return result;
}
Sorry for the long post. Any help would be appreciated.
My listview only update if I drag it up or tapped it till its not getting update with new values.
public void additem(final String name,final String mess) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Messages v=new Messages();
v.setName(name);
v.setmessage(mess);
PersonList.add(v);
mConversationArrayAdapter.notifyDataSetChanged();
mConversationView.invalidateViews();
mConversationView.setSelection(mConversationArrayAdapter.getCount() - 1);
}
});
}
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#null"
android:divider="#null"
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true">
</ListView>
Its because of the transcriptMode set.
android:transcriptMode
Sets the transcript mode for the list. In transcript mode, the list scrolls to the bottom to make new items visible when they are added.
Remove transcriptMode or set it to disabled as a solution for your problem.
Please Refere : http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:transcriptMode