From bc29c578e6f6888387c0baf2da5f383b22af5bfc Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Thu, 26 Oct 2017 19:22:43 +0800 Subject: [PATCH] * fix: webview nested scroll issue * add: image upload support * add: user page --- app/src/main/AndroidManifest.xml | 1 + .../stardust/scriptdroid/network/NodeBB.java | 4 + .../scriptdroid/tool/DrawableSaver.java | 140 ----------------- .../scriptdroid/tool/ImageSelector.java | 20 ++- .../ui/main/community/CommunityFragment.java | 2 +- .../ui/main/community/CommunityWebView.java | 10 +- .../ui/main/drawer/DrawerFragment.java | 38 ++++- .../scriptdroid/ui/user/LoginActivity.java | 7 +- .../ui/user/UserDetailActivity.java | 3 +- .../scriptdroid/ui/user/WebActivity.java | 44 ++++++ .../scriptdroid/ui/widget/AvatarView.java | 6 + .../scriptdroid/ui/widget/EWebView.java | 86 +++++++++-- .../scriptdroid/ui/widget/NestedWebView.java | 141 ++++++++++++++++++ app/src/main/res/layout/activity_web.xml | 29 ++++ app/src/main/res/layout/ewebview.xml | 21 ++- 15 files changed, 372 insertions(+), 180 deletions(-) delete mode 100644 app/src/main/java/com/stardust/scriptdroid/tool/DrawableSaver.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/user/WebActivity.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/widget/NestedWebView.java create mode 100644 app/src/main/res/layout/activity_web.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1542ef7d..7616cb72 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -84,6 +84,7 @@ + diff --git a/app/src/main/java/com/stardust/scriptdroid/network/NodeBB.java b/app/src/main/java/com/stardust/scriptdroid/network/NodeBB.java index d8668ee7..df49ac47 100644 --- a/app/src/main/java/com/stardust/scriptdroid/network/NodeBB.java +++ b/app/src/main/java/com/stardust/scriptdroid/network/NodeBB.java @@ -55,4 +55,8 @@ public class NodeBB { return Observable.just(mConfig); } + + public static String url(String relativePath) { + return BASE_URL + relativePath; + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/DrawableSaver.java b/app/src/main/java/com/stardust/scriptdroid/tool/DrawableSaver.java deleted file mode 100644 index 21560113..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/tool/DrawableSaver.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.stardust.scriptdroid.tool; - -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.widget.ImageView; - -import com.stardust.app.OnActivityResultDelegate; -import com.stardust.pio.PFiles; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Created by Stardust on 2017/4/3. - */ - -public abstract class DrawableSaver { - - private static final String PREFIX = "saved_drawable_"; - - protected Drawable mOriginalDrawable; - private Context mContext; - private String mName; - - public DrawableSaver(Context context, String name, Drawable originalDrawable) { - mContext = context; - mName = PREFIX + name; - mOriginalDrawable = originalDrawable; - readImageAndApply(); - } - - private void readImageAndApply() { - new Thread(new Runnable() { - @Override - public void run() { - try { - InputStream inputStream = mContext.openFileInput(mName); - Drawable drawable = BitmapDrawable.createFromStream(inputStream, mName); - applyDrawableToView(drawable); - } catch (FileNotFoundException e) { - - } - } - }).start(); - } - - public void setDrawable(InputStream inputStream) { - saveDrawable(inputStream, new Runnable() { - @Override - public void run() { - readImageAndApply(); - } - }); - } - - private void saveDrawable(final InputStream inputStream, final Runnable callback) { - new Thread(new Runnable() { - @Override - public void run() { - try { - OutputStream outputStream = mContext.openFileOutput(mName, Context.MODE_PRIVATE); - PFiles.write(inputStream, outputStream); - outputStream.close(); - inputStream.close(); - callback.run(); - } catch (IOException e) { - e.printStackTrace(); - } - } - }).start(); - - } - - public void select(Activity activity, final OnActivityResultDelegate.Mediator mediator) { - new ImageSelector(activity, mediator, new ImageSelector.ImageSelectorCallback() { - @Override - public void onImageSelected(ImageSelector selector, InputStream inputStream) { - if (inputStream != null) - setDrawable(inputStream); - mediator.removeDelegate(selector); - } - }).select(); - } - - public void reset() { - applyDrawableToView(mOriginalDrawable); - mContext.deleteFile(mName); - } - - public static void reset(Context context, String name) { - context.deleteFile(PREFIX + name); - } - - protected abstract void applyDrawableToView(Drawable drawable); - - public static class ViewBackgroundSaver extends DrawableSaver { - - private View mView; - - public ViewBackgroundSaver(Context activity, String name, View view) { - super(activity, name, view.getBackground()); - mView = view; - } - - @Override - protected void applyDrawableToView(final Drawable drawable) { - mView.post(new Runnable() { - @Override - public void run() { - mView.setBackground(drawable); - } - }); - } - } - - public static class ImageSaver extends DrawableSaver { - - private ImageView mView; - - public ImageSaver(Context activity, String name, ImageView view) { - super(activity, name, view.getDrawable()); - mView = view; - } - - @Override - protected void applyDrawableToView(final Drawable drawable) { - mView.post(new Runnable() { - @Override - public void run() { - mView.setImageDrawable(drawable); - } - }); - } - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/ImageSelector.java b/app/src/main/java/com/stardust/scriptdroid/tool/ImageSelector.java index 2462ac6b..56ee252e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tool/ImageSelector.java +++ b/app/src/main/java/com/stardust/scriptdroid/tool/ImageSelector.java @@ -2,6 +2,7 @@ package com.stardust.scriptdroid.tool; import android.app.Activity; import android.content.Intent; +import android.net.Uri; import com.stardust.app.OnActivityResultDelegate; import com.stardust.scriptdroid.R; @@ -16,7 +17,7 @@ import java.io.InputStream; public class ImageSelector implements OnActivityResultDelegate { public interface ImageSelectorCallback { - void onImageSelected(ImageSelector selector, InputStream path); + void onImageSelected(ImageSelector selector, Uri uri); } private static final String TAG = ImageSelector.class.getSimpleName(); @@ -24,11 +25,14 @@ public class ImageSelector implements OnActivityResultDelegate { private static final int REQUEST_CODE = "LOVE EATING".hashCode() >> 16; private Activity mActivity; private ImageSelectorCallback mCallback; + private boolean mDisposable; + private Mediator mMediator; public ImageSelector(Activity activity, OnActivityResultDelegate.Mediator mediator, ImageSelectorCallback callback) { mediator.addDelegate(REQUEST_CODE, this); mActivity = activity; mCallback = callback; + mMediator = mediator; } public void select() { @@ -37,19 +41,21 @@ public class ImageSelector implements OnActivityResultDelegate { REQUEST_CODE); } + public ImageSelector disposable() { + mDisposable = true; + return this; + } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (mDisposable) { + mMediator.removeDelegate(this); + } if (data == null) { mCallback.onImageSelected(this, null); return; } - try { - InputStream inputStream = mActivity.getContentResolver().openInputStream(data.getData()); - mCallback.onImageSelected(this, inputStream); - } catch (FileNotFoundException e) { - mCallback.onImageSelected(this, null); - } + mCallback.onImageSelected(this, data.getData()); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java index d48abee4..1bcff930 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java @@ -89,7 +89,7 @@ public class CommunityFragment extends ViewPagerFragment implements BackPressedH if (isInPostsPage()) { mWebView.loadUrl("javascript:$('button[component=\"topic/reply\"]').click()"); } else { - mWebView.loadUrl("javascript:$('.new_topic').click()"); + mWebView.loadUrl("javascript:$('#new_topic').click()"); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java index 32d4b6ee..f86cd4bd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java @@ -115,18 +115,26 @@ public class CommunityWebView extends EWebView { return super.shouldOverrideUrlLoading(view, url); } + @Override + public void onPageFinished(WebView view, String url) { + evalJavaScript("$('#header').hide();$('#content').css({ top: '0', position: 'absolute' });"); + } } private class MyWebChromeClient extends EWebView.MyWebChromeClient { @Override - public void openFileChooser(ValueCallback callback, String[] acceptType, boolean isCaptureEnabled) { + public boolean openFileChooser(ValueCallback callback, String[] acceptType) { + if (super.openFileChooser(callback, acceptType)) { + return true; + } new FileChooserDialogBuilder(getContext()) .title(R.string.text_select_file_to_upload) .dir(StorageFileProvider.DEFAULT_DIRECTORY_PATH) .singleChoice(file -> callback.onReceiveValue(Uri.fromFile(file))) .cancelListener(dialog -> callback.onReceiveValue(null)) .show(); + return true; } } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java index 67a66e25..316ba074 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java @@ -1,5 +1,6 @@ package com.stardust.scriptdroid.ui.main.drawer; +import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.Nullable; @@ -29,6 +30,8 @@ import com.stardust.scriptdroid.tool.SimpleObserver; import com.stardust.scriptdroid.ui.user.LoginActivity_; import com.stardust.scriptdroid.ui.settings.SettingsActivity; import com.stardust.scriptdroid.ui.update.UpdateInfoDialogBuilder; +import com.stardust.scriptdroid.ui.user.WebActivity; +import com.stardust.scriptdroid.ui.user.WebActivity_; import com.stardust.scriptdroid.ui.widget.AvatarView; import com.stardust.theme.ThemeColorManager; import com.stardust.theme.ThemeColorManagerCompat; @@ -123,20 +126,27 @@ public class DrawerFragment extends android.support.v4.app.Fragment { .me() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::setUpUserInfo, Throwable::printStackTrace); + .subscribe(this::setUpUserInfo, error -> { + error.printStackTrace(); + setUpUserInfo(null); + }); } - private void setUpUserInfo(User user) { - mUserName.setText(user.getUsername()); - mAvatar.setUser(user); + private void setUpUserInfo(@Nullable User user) { + if (user == null) { + mUserName.setText(R.string.not_login); + mAvatar.setIcon(R.drawable.profile_avatar_placeholder); + } else { + mUserName.setText(user.getUsername()); + mAvatar.setUser(user); + } setCoverImage(user); } private void setCoverImage(User user) { - String coverUrl = user.getCoverUrl(); - if (TextUtils.isEmpty(coverUrl) || coverUrl.equals("/assets/images/cover-default.png")) { + if (user == null || TextUtils.isEmpty(user.getCoverUrl()) || user.getCoverUrl().equals("/assets/images/cover-default.png")) { mDefaultCover.setVisibility(View.VISIBLE); mShadow.setVisibility(View.GONE); mHeaderView.setBackgroundColor(ThemeColorManagerCompat.getColorPrimary()); @@ -144,7 +154,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { mDefaultCover.setVisibility(View.GONE); mShadow.setVisibility(View.VISIBLE); GlideApp.with(getContext()) - .load(NodeBB.BASE_URL + coverUrl) + .load(NodeBB.BASE_URL + user.getCoverUrl()) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(new SimpleTarget() { @Override @@ -157,7 +167,19 @@ public class DrawerFragment extends android.support.v4.app.Fragment { @Click(R.id.avatar) void loginOrShowUserInfo() { - LoginActivity_.intent(getActivity()).start(); + NodeBB.getInstance().getRetrofit() + .create(UserApi.class) + .me() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((user -> { + WebActivity_.intent(this) + .extra(WebActivity.EXTRA_URL, NodeBB.url("user/" + user.getUserslug())) + .extra(Intent.EXTRA_TITLE, user.getUsername()) + .start(); + }), error -> { + LoginActivity_.intent(getActivity()).start(); + }); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/user/LoginActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/user/LoginActivity.java index ef8e7d05..4661d02c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/user/LoginActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/user/LoginActivity.java @@ -1,5 +1,6 @@ package com.stardust.scriptdroid.ui.user; +import android.annotation.SuppressLint; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; @@ -8,6 +9,7 @@ import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.network.NodeBB; import com.stardust.scriptdroid.network.UserService; import com.stardust.scriptdroid.ui.BaseActivity; @@ -66,7 +68,10 @@ public class LoginActivity extends BaseActivity { @Click(R.id.forgot_password) void forgotPassword() { - + WebActivity_.intent(this) + .extra(WebActivity.EXTRA_URL, NodeBB.BASE_URL + "reset") + .extra(Intent.EXTRA_TITLE, getString(R.string.text_reset_password)) + .start(); } private boolean checkNotEmpty(String userName, String password) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/user/UserDetailActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/user/UserDetailActivity.java index 5096ebca..24801477 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/user/UserDetailActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/user/UserDetailActivity.java @@ -6,5 +6,6 @@ import com.stardust.scriptdroid.ui.BaseActivity; * Created by Stardust on 2017/10/26. */ -public class UserDetailActivity extends BaseActivity { +public class UserDetailActivity extends WebActivity { + } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/user/WebActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/user/WebActivity.java new file mode 100644 index 00000000..d7f5905d --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/user/WebActivity.java @@ -0,0 +1,44 @@ +package com.stardust.scriptdroid.ui.user; + +import android.content.Intent; +import android.support.annotation.NonNull; + +import com.stardust.app.OnActivityResultDelegate; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.ui.widget.EWebView; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.EActivity; +import org.androidannotations.annotations.ViewById; + +/** + * Created by Stardust on 2017/10/26. + */ +@EActivity(R.layout.activity_web) +public class WebActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHost { + + public static final String EXTRA_URL = "url"; + + private OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator(); + + @ViewById(R.id.eweb_view) + EWebView mEWebView; + + @AfterViews + void setupViews() { + setToolbarAsBack(getIntent().getStringExtra(Intent.EXTRA_TITLE)); + mEWebView.getWebView().loadUrl(getIntent().getStringExtra(EXTRA_URL)); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mMediator.onActivityResult(requestCode, resultCode, data); + } + + @NonNull + @Override + public OnActivityResultDelegate.Mediator getOnActivityResultDelegateMediator() { + return mMediator; + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/widget/AvatarView.java b/app/src/main/java/com/stardust/scriptdroid/ui/widget/AvatarView.java index 13f4a834..ded4b63d 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/widget/AvatarView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/widget/AvatarView.java @@ -64,6 +64,12 @@ public class AvatarView extends FrameLayout { mIconTextBackground = (GradientDrawable) mIconText.getBackground(); } + public void setIcon(int resId) { + mIcon.setVisibility(View.VISIBLE); + mIconText.setVisibility(View.GONE); + mIcon.setImageResource(resId); + } + public void setUser(final User user) { if (TextUtils.isEmpty(user.getPicture())) { mIcon.setVisibility(View.GONE); diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/widget/EWebView.java b/app/src/main/java/com/stardust/scriptdroid/ui/widget/EWebView.java index 9e008e68..82cd5226 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/widget/EWebView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/widget/EWebView.java @@ -1,6 +1,7 @@ package com.stardust.scriptdroid.ui.widget; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -18,19 +19,34 @@ import android.webkit.WebViewClient; import android.widget.FrameLayout; import android.widget.ProgressBar; +import com.stardust.app.OnActivityResultDelegate; import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.tool.ImageSelector; +import com.stardust.util.IntentUtil; +import org.androidannotations.annotations.OnActivityResult; import org.androidannotations.annotations.ViewById; +import java.io.File; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; + /** * Created by Stardust on 2017/8/22. */ -public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefreshListener { +public class EWebView extends SwipeRefreshLayout implements SwipeRefreshLayout.OnRefreshListener, OnActivityResultDelegate { + + private static final List IMAGE_TYPES = Arrays.asList("png", "jpg", "bmp"); + private static final int CHOOSE_IMAGE = 42222; private WebView mWebView; private ProgressBar mProgressBar; - SwipeRefreshLayout mSwipeRefreshLayout; public EWebView(Context context) { super(context); @@ -47,8 +63,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres inflate(getContext(), R.layout.ewebview, this); mWebView = (WebView) findViewById(R.id.web_view); mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); - mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); - mSwipeRefreshLayout.setOnRefreshListener(this); + setOnRefreshListener(this); setUpWebView(); } @@ -69,9 +84,26 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres return mWebView; } + public void evalJavaScript(String script) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + mWebView.evaluateJavascript(script, null); + } else { + mWebView.loadUrl("javascript:" + script); + } + } + @Override public void onRefresh() { mWebView.reload(); + Observable.timer(2, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(t -> setRefreshing(false)); + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + } protected class MyWebChromeClient extends WebChromeClient { @@ -85,12 +117,21 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres //For Android >= 4.1 public void openFileChooser(ValueCallback valueCallback, String acceptType, String capture) { - openFileChooser(valueCallback, acceptType.split(","), capture.equals("true")); + if (acceptType == null) { + openFileChooser(valueCallback, null); + } else { + openFileChooser(valueCallback, acceptType.split(",")); + } } - public void openFileChooser(ValueCallback valueCallback, - String[] acceptType, boolean isCaptureEnabled) { - + public boolean openFileChooser(ValueCallback valueCallback, + String[] acceptType) { + if (getContext() instanceof OnActivityResultDelegate.DelegateHost && + getContext() instanceof Activity && isImageType(acceptType)) { + chooseImage(valueCallback); + return true; + } + return false; } // For Android >= 5.0 @@ -105,9 +146,34 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres } else { filePathCallback.onReceiveValue(new Uri[]{value}); } - }, fileChooserParams.getAcceptTypes(), fileChooserParams.isCaptureEnabled()); + }, fileChooserParams.getAcceptTypes()); return true; } + + + } + + private void chooseImage(ValueCallback valueCallback) { + DelegateHost delegateHost = ((OnActivityResultDelegate.DelegateHost) getContext()); + Mediator mediator = delegateHost.getOnActivityResultDelegateMediator(); + Activity activity = (Activity) getContext(); + new ImageSelector(activity, mediator, (selector, uri) -> valueCallback.onReceiveValue(uri)) + .disposable() + .select(); + } + + private boolean isImageType(String[] acceptTypes) { + if (acceptTypes == null) { + return false; + } + for (String acceptType : acceptTypes) { + for (String imageType : IMAGE_TYPES) { + if (acceptType.contains(imageType)) { + return true; + } + } + } + return false; } protected class MyWebViewClient extends WebViewClient { @@ -123,7 +189,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mProgressBar.setVisibility(GONE); - mSwipeRefreshLayout.setRefreshing(false); + setRefreshing(false); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/widget/NestedWebView.java b/app/src/main/java/com/stardust/scriptdroid/ui/widget/NestedWebView.java new file mode 100644 index 00000000..b8e7bfc7 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/widget/NestedWebView.java @@ -0,0 +1,141 @@ +package com.stardust.scriptdroid.ui.widget;/* + * Copyright (C) 2015 takahirom + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import android.content.Context; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.NestedScrollingChild; +import android.support.v4.view.NestedScrollingChildHelper; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.webkit.WebView; + +public class NestedWebView extends WebView implements NestedScrollingChild { + private int mLastY; + private final int[] mScrollOffset = new int[2]; + private final int[] mScrollConsumed = new int[2]; + private int mNestedOffsetY; + private NestedScrollingChildHelper mChildHelper; + + public NestedWebView(Context context) { + this(context, null); + } + + public NestedWebView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.webViewStyle); + } + + public NestedWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mChildHelper = new NestedScrollingChildHelper(this); + setNestedScrollingEnabled(true); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + boolean returnValue = false; + + MotionEvent event = MotionEvent.obtain(ev); + final int action = MotionEventCompat.getActionMasked(event); + if (action == MotionEvent.ACTION_DOWN) { + mNestedOffsetY = 0; + } + int eventY = (int) event.getY(); + event.offsetLocation(0, mNestedOffsetY); + switch (action) { + case MotionEvent.ACTION_MOVE: + int deltaY = mLastY - eventY; + // NestedPreScroll + if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) { + deltaY -= mScrollConsumed[1]; + mLastY = eventY - mScrollOffset[1]; + event.offsetLocation(0, -mScrollOffset[1]); + mNestedOffsetY += mScrollOffset[1]; + } + returnValue = super.onTouchEvent(event); + + // NestedScroll + if (dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) { + event.offsetLocation(0, mScrollOffset[1]); + mNestedOffsetY += mScrollOffset[1]; + mLastY -= mScrollOffset[1]; + } + break; + case MotionEvent.ACTION_DOWN: + returnValue = super.onTouchEvent(event); + mLastY = eventY; + // start NestedScroll + startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + returnValue = super.onTouchEvent(event); + // end NestedScroll + stopNestedScroll(); + break; + } + return returnValue; + } + + // Nested Scroll implements + @Override + public void setNestedScrollingEnabled(boolean enabled) { + mChildHelper.setNestedScrollingEnabled(enabled); + } + + @Override + public boolean isNestedScrollingEnabled() { + return mChildHelper.isNestedScrollingEnabled(); + } + + @Override + public boolean startNestedScroll(int axes) { + return mChildHelper.startNestedScroll(axes); + } + + @Override + public void stopNestedScroll() { + mChildHelper.stopNestedScroll(); + } + + @Override + public boolean hasNestedScrollingParent() { + return mChildHelper.hasNestedScrollingParent(); + } + + @Override + public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, + int[] offsetInWindow) { + return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { + return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { + return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedPreFling(float velocityX, float velocityY) { + return mChildHelper.dispatchNestedPreFling(velocityX, velocityY); + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_web.xml b/app/src/main/res/layout/activity_web.xml new file mode 100644 index 00000000..a6303c17 --- /dev/null +++ b/app/src/main/res/layout/activity_web.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/ewebview.xml b/app/src/main/res/layout/ewebview.xml index cb9ca6b7..a3892c8c 100644 --- a/app/src/main/res/layout/ewebview.xml +++ b/app/src/main/res/layout/ewebview.xml @@ -1,26 +1,25 @@ - - - - - + + \ No newline at end of file