I want use PullToRefresh but in my application I don't use recyclerview, and use this widget : android.support.v4.widget.NestedScrollView.
I should set pull to refresh to load new data in my application, how can I it?
Please don't offer to me for use RecyclerView, because I haven't use RecyclerView.
I want use android.support.v4.widget.NestedScrollView .
How can I it?
Use SwipeRefreshLayout
this.srl1 = (SwipeRefreshLayout) findViewById(R.id.srl);
if (srl1 != null) {
srl1.setColorSchemeResources(R.color.red, R.color.green, R.color.blue);
srl1.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Refresh();
}
});
}
XML CODE
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/srl"
>
</android.support.v4.widget.SwipeRefreshLayout>
Related
I have created a project of type "Android App (Xamarin)" in VS2019 which has the following activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView
android:id="#+id/web"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
I have code that uses the pipes a value from the built in NFC reader on Samsung tablet to the web page loaded into the WebView, and all is working well.
However, if a page load stalls or the user gets an error in the web page for some reason, there is no way to refresh the page. I wanted to add a pull down to refresh, and also a pull from left to right to go back would be pretty cool as well, but will focus on pull to refresh in this post.
I found a Xamarin Forms example of how to use the RefreshView to achieve this, but it doesn't seem to work in the Android only project.
How can I use the RefreshView in my "Android App (Xamarin)" project, or is there a better way to do this?
I am targeting Android 9.0.
Thanks for your time.
A simple sample like below:
public class RefreshWebView : Activity,SwipeRefreshLayout.IOnRefreshListener,SwipeRefreshLayout.IOnChildScrollUpCallback
{
private WebView webView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.refresh_webview);
SwipeRefreshLayout swipeRefreshLayout = FindViewById<SwipeRefreshLayout>(Resource.Id.swipe_fresh);
webView = FindViewById<WebView>(Resource.Id.web);
webView.LoadUrl("https://www.google.com");
webView.SetWebViewClient(new MyWebClient(swipeRefreshLayout));
swipeRefreshLayout.SetOnRefreshListener(this);
swipeRefreshLayout.SetOnChildScrollUpCallback(this);
}
public void OnRefresh()
{
webView.LoadUrl(webView.Url.ToString());
}
public bool CanChildScrollUp(SwipeRefreshLayout parent, View child)
{
return webView.ScrollY > 0;
}
class MyWebClient : WebViewClient
{
SwipeRefreshLayout swipeRefresh;
public MyWebClient(SwipeRefreshLayout swipeRefreshLayout)
{
swipeRefresh = swipeRefreshLayout;
}
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return true;
}
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
if (swipeRefresh.Refreshing)
{
swipeRefresh.Refreshing = false;
}
}
}
}
xaml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_fresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<WebView
android:id="#+id/web"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
I am using two RecyclerViews in my app, one in the MainActivity and one in another activity. The one in the MainActivity works fine but the other has a NullPointerException and I don't know where the problem here is.
Here is a code snippet of the second RecyclerView, where the logcat says that there is a Null object reference. I used the same code as the first RecyclerView where everything works.
The error message says that there is a problem in this line: recyclerView.setLayoutManager(layoutManager);
and in this line
initRecyclerViewFriendOverView();
Here is where I implemented my second RecyclerView:
private void initRecyclerViewFriendOverView() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
RecyclerView recyclerView = findViewById(R.id.recyclerViewFriendOverView);
recyclerView.setLayoutManager(layoutManager);
RecyclerViewAdapterFriendOverView adpater = new RecyclerViewAdapterFriendOverView(mNames, mImageUrls, this);
recyclerView.setAdapter(adpater);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_overview);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
init();
initRecyclerViewFriendOverView();
getImages();
}
Here ist the XML where the second RecyclerView is used:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewFreundesUebersicht"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Edit:
The problem was that I called the RecyclerView before initializing it in the onCreate method.
EDIT:
You are including another xml file in your activity using include statement, findViewById() won't be able to find views from included layouts. Give an id to your include statement, find that included view first and then call findViewById () in that view:
In Activity layout file:
<include id="includedRecyclerLayout"
....
</include>
And in your code:
ConstraintLayout includedLayout = findViewById(R.id.inckudedRecyclerLayout);
RecyclerView recyclerview = includedLayout.findViewById(R.id.RECYCLER_VIEW_ID);
If it shows error at recyclerView.setLayoutManager(layoutManager); it means your recyclerView is null. Then you look at where you initialized it:
RecyclerView recyclerView = findViewById(R.id.recyclerViewFreundesUebersicht);
It can be null because of two reasons:
You didn't add the RecyclerView to XML
Your R.id.recyclerViewFreundesUebersicht is referring to a view from another xml
Check your XML and make sure your recyclerview was added to XML and the id you are using here is same as the one used in activity.
Initialize LinearLayoutManager like this
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
How can i set up my RecyclerView properly to detect swipe Up and Down?
When i place recycler.setOnTouchListener(this)
I get this warning: recyclerview has setontouchlistener but does not override perfoclick and nothing works.
Thank you.
recyclerView = (RecyclerView)rootview.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(layoutManager);
Adapter adapter=new
Adapter (List);
recyclerView.setAdapter(adapter);
You should be using SwipeRefreshLayout and handle the callback with setOnRefreshListener example.
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
SwipeRefreshLayout mSwRefresh=findViewById(R.id.SwRefresh);;
mSwRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
//TODO:
}
});
I am looking for a way to show a progressbar like the one below (which i just saw in recyclerView)
Please check this it will solve your problem
android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
// put your layout here
</android.support.v4.widget.SwipeRefreshLayout>
And activity code would be
SwipeRefreshLayout mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
refreshContent();
...
}
UPDATE: I thought it worked correctly. But after some test trouble still exists *sniff*
Then I made a simpler version to see what exactly happen and I get to know that the refreshing fragment which should have been detached still left there. Or exactly, the view of the old fragment left there, on top of the newer fragment. Since RecyclerView's background of my original app is not transparent, so It turned out what I said before.
END OF UPDATE
I have a MainActivity with layout like this:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="#+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="#+id/container" android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
The fragment ContentView I use to fill #id/container is configured as:
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300"/>
</android.support.v4.widget.SwipeRefreshLayout>
And here is onCreateView() of ContentView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View inflatedView = inflater.inflate(R.layout.fragment_content, container, false);
mRecyclerView = (RecyclerView) inflatedView.findViewById(R.id.tweet_list);
mRecyclerView.setHasFixedSize(false);
mLinearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mTweetList = new ArrayList<Tweet>;
mAdapter = new TweetAdapter(mTweetList);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mSwipeRefreshLayout = (SwipeRefreshLayout) inflatedView.findViewById(R.id.contentView);
mSwipeRefreshLayout.setOnRefreshListener(
...
);
return inflatedView;
}
Then in MainActivity I switch the content to display by switching different ContentView. All looks good except one thing: when I switch ContentView fragments DURING refreshing by navigation drawer, then content freezes. But actually all things work as usual except you cannot see it.
Well... After some struggling I eventually solved this problem by myself, in a tricky way...
I just need to add these in onPause() :
#Override
public void onPause() {
super.onPause();
...
if (mSwipeRefreshLayout!=null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
}
This issue seems to still be occurring in appcompat 22.1.1. Wrapping the SwipeRefreshLayout inside a FrameLayout solved this for me
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
In addition to #zlm2012 answer, I noticed that this issue was reproduced under Support Library 21.0.0, but seems to be fixed right now at 21.0.3
The solution works, but I think it is better just put those lines into its own function, like:
public void terminateRefreshing() {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
and call when switching the fragment.
Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);
if(prevFrag instanceof SwipeRefreshFragment) {
((SwipeRefreshFragment)prevFrag).terminateRefreshing();
}
fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();
It works! Just remove the transition from your fragment replacement, in my case I removed the following from my code:
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
Set clickable="true" in top parent layout... It may solve the problem.
For the time being, you can avoid the issue by:
public class FixedRefreshLayout extends SwipeRefreshLayout {
private static final String TAG = "RefreshTag";
private boolean selfCancelled = false;
public FixedRefreshLayout(Context context) {
super(context);
}
public FixedRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected Parcelable onSaveInstanceState()
{
if(isRefreshing()) {
clearAnimation();
setRefreshing(false);
selfCancelled = true;
Log.d(TAG, "For hide refreshing");
}
return super.onSaveInstanceState();
}
#Override
public void setRefreshing(boolean refreshing) {
super.setRefreshing(refreshing);
selfCancelled = false;
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(hasWindowFocus && selfCancelled) {
setRefreshing(true);
Log.d(TAG, "Force show refreshing");
}
}
}
This has the added advantage of resuming the animation incase you decide to not switch the fragment (coming from some menu). It also ties in with the internal animation to make sure that the refreshing animation does not return if the network refresh has already completed.
Terminate SwipeRefresh whenever navigation menu item is clicked.
It worked.
private void selectItem(int position) {
mSwipeRefreshLayout.setRefreshing(false);
/*
Other part of the function
*/
}