I have a web page with image and some text, image is having parallax effect. when i am loading the web page in a web view which is inside a scroll view, the parallax effect is not working. Scroll view also have recycler view along with web view. How to achieve the parallax effect in web page as well as seamless scroll for the whole page?
This video have the page i have developed with web view inside scroll view
This video is the demo screen with only web view, just to test the parallax in the web page
Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parent_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_detail_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="@+id/related"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_divider_height"
android:background="#dedede"
android:visibility="visible" />
<TextView
android:id="@+id/related_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/view"
android:layout_margin="@dimen/main_margin"
android:text="@string/related_news"
android:textColor="@android:color/black"
android:textSize="@dimen/list_item_title"
android:textStyle="bold"
android:visibility="visible" />
<android.support.v7.widget.RecyclerView
android:id="@+id/related_article"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/related_title"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:visibility="visible" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/recommendation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<View
android:id="@+id/recommendation_seperator"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_divider_height"
android:background="#dedede"
android:visibility="visible" />
<TextView
android:id="@+id/recommendation_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/main_margin"
android:text="Sponsored Stories"
android:textColor="@android:color/black"
android:textSize="@dimen/list_item_title"
android:textStyle="bold" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_margin="@dimen/main_margin"
android:orientation="horizontal">
<TextView
android:id="@+id/drawer_title_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:text="Recommended by "
android:textColor="@color/black_semi_trans"
android:textSize="12dp"
android:textStyle="bold" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_recommendation" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recommendation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/recommendation_title" />
</RelativeLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
Java Class
public class NewsDetailFragment extends Fragment implements ViewModel.ResponseListener<News>, RecyclerViewEvents.Listener<Object>,
View.OnKeyListener, RecommendationsListener {
private List<NewsItem> relatedList = new ArrayList<>();
private RelatedArticleListAdapter relatedAdapter;
private String url;
private ClickEvents.ListItemListener listItemListener;
private WebView webView;
private ProgressBar progressBar;
private boolean isWebViewPaused;
private List<OBRecommendation> outbrainList = new ArrayList();
private OutbrainAdapter outbrainAdapter;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
listItemListener = (ClickEvents.ListItemListener) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
url = getArguments().getString(Constants.BundleKeys.URL);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate((Network.isConnected(getActivity())) ? R.layout.fragment_news_detail : R.layout.fragment_news_detail_offline, container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
webView = (WebView) view.findViewById(R.id.web_view);
webView.setHorizontalScrollBarEnabled(false);
webView.getSettings().setAppCacheEnabled(false);
webView.setScrollBarStyle(WebView.SCROLLBARS_INSIDE_INSET);
webView.setVerticalScrollBarEnabled(false);
webView.setOnKeyListener(this);
webView.getSettings().setJavaScriptEnabled(true);
int fontSize = PreferenceManager.getsInstance(getActivity()).getSharedPrefs().getInt(PreferenceManager.PreferenceKeys.SETTINGS_CURRENT_FONT_SIZE, -1);
switch (fontSize) {
case 0: //LARGE
webView.getSettings().setTextZoom(160);
break;
case 1: // MEDIUM
webView.getSettings().setTextZoom(130);
break;
case 2: //NORMAL
webView.getSettings().setTextZoom(100);
break;
case 3: //SMALL
webView.getSettings().setTextZoom(70);
break;
default:
webView.getSettings().setTextZoom(100);
}
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (Network.isConnected(getActivity())) {
RecyclerView relatedRecyclerView = (RecyclerView) getView().findViewById(R.id.related_article);
RecyclerView recommendationRecyclerView = (RecyclerView) getView().findViewById(R.id.recommendation_view);
RelativeLayout recommendationLayout = (RelativeLayout) getView().findViewById(R.id.recommendation);
RelativeLayout relatedLayout = (RelativeLayout) getView().findViewById(R.id.related);
webView.setWebViewClient(new WebClient(progressBar, recommendationLayout, relatedLayout));
relatedRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
relatedRecyclerView.setAdapter(relatedAdapter = new RelatedArticleListAdapter(getActivity(), relatedList, this));
OBRequest request = new OBRequest(url, getResources().getString(R.string.outbrain_widget));
Outbrain.fetchRecommendations(request, this);
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
recommendationRecyclerView.setLayoutManager(layoutManager);
outbrainAdapter = new OutbrainAdapter(getActivity(), outbrainList, this);
recommendationRecyclerView.setAdapter(outbrainAdapter);
webView.loadUrl(url);
String keywords = getArguments().getString(Constants.BundleKeys.KEYWORDS);
if (keywords != null) {
String newsId = getArguments().getString(Constants.BundleKeys.NEWS_ID);
String url = ConfigManager.getsInstance().getURL(Constants.CustomApiType.RELATED_NEWS);
StringBuilder builder = new StringBuilder(url).append("&").append(APIService.QueryKeys.EXCLUDE_ID)
.append("=").append(newsId)
.append("&").append(APIService.QueryKeys.ALL_FIELDS).append("=")
.append(keywords);
NewsViewModel newsViewModel = new NewsViewModel(getActivity(), this, builder.toString());
newsViewModel.downloadRelatedNews();
}
} else {
webView.setWebViewClient(new WebClient(progressBar));
downloadCachedHTML(url);
}
}
private void downloadCachedHTML(String url) {
boolean isBookMarkNews = getArguments().getBoolean(Constants.BundleKeys.IS_BOOKMARK, false);
HTMLClient client = HTMLClientFactory.create(getActivity(), isBookMarkNews ? CacheInfo.BOOKMARK_NEWS : CacheInfo.NEWS_DETAIL);
HTMLAPIService apiService = client.getAPIService(HTMLAPIService.class);
Call<String> call = apiService.downloadHtml(url);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if (getActivity() == null)
return;
progressBar.setVisibility(View.GONE);
if (response.body() != null) {
webView.loadDataWithBaseURL("", response.body(), "text/html", "utf-8", null);
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
progressBar.setVisibility(View.GONE);
}
});
}
@Override
public void onItemClick(Object item, View v, int position) {
if (item instanceof NewsItem) {
News news = new News();
news.newsList = relatedList;
listItemListener.onNewsListItemClick(news, position, "", false);
}
if (item instanceof OBRecommendation)
listItemListener.onRecommendationItemClick(((OBRecommendation) item).getUrl());
}
@Override
public void onResponse(News response) {
relatedList.clear();
relatedList.addAll(response.newsList);
relatedAdapter.notifyDataSetChanged();
}
@Override
public void onNextResponse(News response) {
}
@Override
public void onNextError() {
}
@Override
public void onError() {
relatedList.clear();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getActivity() == null)
return;
if (webView == null)
return;
if (isVisibleToUser)
webView.onResume();
else webView.onPause();
}
@Override
public void onPause() {
super.onPause();
webView.onPause();
isWebViewPaused = true;
}
@Override
public void onResume() {
super.onResume();
if (isWebViewPaused) {
webView.onResume();
isWebViewPaused = false;
}
}
@Override
public void onOutbrainRecommendationsSuccess(OBRecommendationsResponse recommendations) {
outbrainList.clear();
outbrainList.addAll(recommendations.getAll());
outbrainAdapter.notifyDataSetChanged();
}
@Override
public void onOutbrainRecommendationsFailure(Exception ex) {
outbrainList.clear();
}
private class WebClient extends WebViewClient {
private final ProgressBar progressBar;
private RelativeLayout recommendation;
private RelativeLayout related;
public WebClient(ProgressBar progressBar, RelativeLayout recommendation, RelativeLayout related) {
this.progressBar = progressBar;
this.recommendation = recommendation;
this.related = related;
}
public WebClient(ProgressBar progressBar) {
this.progressBar = progressBar;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
progressBar.setVisibility(View.VISIBLE);
if (Network.isConnected(getActivity())) {
recommendation.setVisibility(View.GONE);
related.setVisibility(View.GONE);
}
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
progressBar.setVisibility(View.GONE);
if (Network.isConnected(getActivity())) {
related.setVisibility(relatedList.isEmpty() ? View.GONE : View.VISIBLE);
recommendation.setVisibility(outbrainList.isEmpty() ? View.GONE : View.VISIBLE);
}
}
@SuppressWarnings("deprecation")
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (!Network.isConnected(getActivity())) {
WebResourceResponse response = getResponse(url);
return response == null ? super.shouldInterceptRequest(view, url) : response;
}
return super.shouldInterceptRequest(view, url);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
if (!Network.isConnected(getActivity())) {
String url = request.getUrl().toString();
WebResourceResponse response = getResponse(url);
return response == null ? super.shouldInterceptRequest(view, request) : response;
}
return super.shouldInterceptRequest(view, request);
}
@Nullable
private WebResourceResponse getResponse(String url) {
if (url.endsWith(".png") || url.endsWith(".jpg")) {
boolean isBookMarkNews = getArguments().getBoolean(Constants.BundleKeys.IS_BOOKMARK, false);
HTMLClient client = HTMLClientFactory.create(getActivity(), isBookMarkNews ? CacheInfo.BOOKMARK_NEWS : CacheInfo.NEWS_DETAIL);
File cachedFile = new File(client.getImageDir() + File.separator + HTMLInterceptor.getFileName(url));
if (cachedFile.exists()) {
try {
return new WebResourceResponse(
"image/*", "utf-8", new FileInputStream(cachedFile));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
return null;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Network.isConnected(progressBar.getContext()))
return false;
else return true;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return super.shouldOverrideUrlLoading(view, url);
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
WebView webView = (WebView) v;
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (webView.canGoBack()) {
webView.goBack();
return true;
}
break;
}
}
return false;
}
@Override
public void onDestroyView() {
super.onDestroyView();
webView.destroy();
}
}