【问题标题】:Android: Making a button visible once webview is done scrollingAndroid:一旦 webview 完成滚动,就使按钮可见
【发布时间】:2019-08-02 12:35:31
【问题描述】:

我有一个显示 html 文件的 webview。当用户在 webview 中滚动到该文件的底部时,我希望显示一个以前隐藏的按钮,然后用户可以按下该按钮来进行一些活动

我在 iOS 中做了类似的事情,我只是将委托设置为 ViewController 并将按钮设置为可见。我如何在 Android 上做类似的事情?我注意到没有像 iOS 那样的回调方法。

编辑:现在,我有一个包含 2 个对象的活动:一个包含我的文本的 web 视图和一个当前不可见的按钮。我希望我的活动在 webview 文本滚动到底部时收到一条消息,并使按钮可见

【问题讨论】:

    标签: android delegates scroll android-webview


    【解决方案1】:

    我必须自己执行此操作,以便在用户滚动到 EULA 底部后显示“我同意”按钮。律师,嗯?

    事实上,当您覆盖 WebView(而不是 @JackTurky 的答案中的 ScrollView)时,您可以调用 computeVerticalScrollRange() 来获取内容的高度,而不是 getBottom() 返回可见底部而不是有用。

    这是我的综合解决方案。据我所知,这都是 API Level 1 的东西,所以它应该可以在任何地方工作。

    public class EulaWebView extends WebView {
        public EulaWebView(Context context) 
        {
            this(context, null);
        }
    
        public EulaWebView(Context context, AttributeSet attrs) 
        {
            this(context, attrs, 0);
        }
    
        public EulaWebView(Context context, AttributeSet attrs, int defStyle) 
        {
            super(context, attrs, defStyle);
        }
    
        public OnBottomReachedListener mOnBottomReachedListener = null;
        private int mMinDistance = 0;
    
        /**
         * Set the listener which will be called when the WebView is scrolled to within some
         * margin of the bottom.
         * @param bottomReachedListener
         * @param allowedDifference
         */
        public void setOnBottomReachedListener(OnBottomReachedListener bottomReachedListener, int allowedDifference ) {
            mOnBottomReachedListener = bottomReachedListener;
            mMinDistance = allowedDifference;
        }
    
        /**
         * Implement this interface if you want to be notified when the WebView has scrolled to the bottom.
         */
        public interface OnBottomReachedListener {
            void onBottomReached(View v);
        }
    
        @Override
        protected void onScrollChanged(int left, int top, int oldLeft, int oldTop) {
            if ( mOnBottomReachedListener != null ) {
                if ( (computeVerticalScrollRange() - (top + getHeight())) <= mMinDistance )
                    mOnBottomReachedListener.onBottomReached(this);
            }
            super.onScrollChanged(left, top, oldLeft, oldTop);
        }
    
    }
    

    一旦用户滚动到 WebView 的底部,我就使用它来显示“我同意”按钮,我在这里这样称呼它(在“实现 OnBottomReachedListener”的类中:

    EulaWebView mEulaContent;
    Button mEulaAgreed;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.eula);
        mEulaContent = (EulaWebView) findViewById(R.id.eula_content);
        StaticHelpers.loadWebView(this, mEulaContent, R.raw.stylesheet, StaticHelpers.readRawTextFile(this, R.raw.eula), null);
        mEulaContent.setVerticalScrollBarEnabled(true);
        mEulaContent.setOnBottomReachedListener(this, 50);
    
        mEulaAgreed = (Button) findViewById(R.id.eula_agreed);
        mEulaAgreed.setOnClickListener(this);
        mEulaAgreed.setVisibility(View.GONE);
    }
    
    @Override
    public void onBottomReached(View v) {
        mEulaAgreed.setVisibility(View.VISIBLE);
    }
    

    所以当到达底部时(或者在这种情况下,当他们到达底部 50 像素以内时)“我同意”按钮就会出现。

    【讨论】:

    • 您好,请告诉我StaticHelpers 是在哪里声明的?
    • StaticHelpers 是一个带有一些通用方法的内部类 - 在这种情况下用于加载 web 视图,并用于从文件系统读取文本文件 - 没有什么特别令人吃惊的。
    • 不错!我只是使用 computeVerticalScrollRange() 而不是 getContentHeight() 来让它工作
    【解决方案2】:

    [我无法对答案发表评论,所以将我的评论留在这里作为新答案]

    karora 的答案(第一个)效果很好,除了在

    protected void onScrollChanged(int left, int top, int oldLeft, int oldTop)
    

    方法,调用

    getContentHeight()
    

    对我来说非常不准确。它报告的值太小了,所以当用户仅向下滚动 WebView 的三分之一时调用了我的侦听器。我用过

    computeVerticalScrollRange()
    

    相反,这是完美的。感谢 this post 提供的有用提示。

    【讨论】:

    • computeVerticalScrollRange() 好像已经改成了受保护的访问,所以这行不行了。
    【解决方案3】:

    试试这个:

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            View view = (View) getChildAt(getChildCount()-1);
            int diff = (view.getBottom()-(getHeight()+getScrollY()));// Calculate the scrolldiff
            if( diff == 0 ){  // if diff is zero, then the bottom has been reached
                Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" );
                yourButton.setVisible(true);
            }
            super.onScrollChanged(l, t, oldl, oldt);
    }
    

    要实现这一点,请扩展 ScrollView,然后重写 onScrollChanged 方法(继承自 View)。

    【讨论】:

    • webview 没有对按钮的引用。
    【解决方案4】:

    仅当 webview 到达/滚动到底部时加载/可见按钮。

    创建 JavaScript 类:

    public class JavaScriptInterface {
    
      @android.webkit.JavascriptInterface
      public void didScrollToBottom() {
        Log.d(TAG, "Scroll to Bottom");
        myHandler.post(new Runnable() {
          @Override
          public void run() {
             btnAccept.setVisibility(View.VISIBLE);
    
              }
           });
          }
        }
    

    在 onCreate() 中:

    final JavaScriptInterface jsInterface = new JavaScriptInterface();
    myWebView.addJavascriptInterface(jsInterface, "AndroidFunction");
    

    【讨论】:

      【解决方案5】:

      对于类似的问题,上述解决方案对我来说并不完全有效(滚动 webView 时隐藏按钮,滚动结束后显示)。我希望它在滚动时隐藏的原因是因为我想隐藏的按钮是为了跳到 webview 的最底部,当它只在 webview 是静态的时候才对我有用,但在视图仍然存在时没有跳到底部滚动。 所以我做了以下事情:

      为覆盖的 webView 添加了一个 onScrollChanged 回调,就像附近建议的那样:

      private OnScrollChangedCallback mOnScrollChangedCallback;
      
      public OnScrollChangedCallback getOnScrollChangedCallback() {
          return mOnScrollChangedCallback;
      }
      
      public void setOnScrollChangedCallback(
              final OnScrollChangedCallback onScrollChangedCallback) {
          mOnScrollChangedCallback = onScrollChangedCallback;
      }
      
      @Override
      protected void onScrollChanged(final int l, final int t, final int oldl,
              final int oldt) {
          super.onScrollChanged(l, t, oldl, oldt);
          if (mOnScrollChangedCallback != null){
              mOnScrollChangedCallback.onScrollChanged(l, t);
          }
      }
      
      /**
       * Implement in the activity/fragment/view that you want to listen to the
       * webview
       */
      public static interface OnScrollChangedCallback {
          public void onScrollChanged(int l, int t);
      }
      

      在我的实现 OnScrollChangedCallback 的活动类中

      更新:

      Timer timer2showJumpButton;
      private long lastScrollEventTimestamp;
      public final static int HIDING_JUMP_BUTTON_ON_SCROLL_DELAY  = 500;
      
          public void onScrollChanged(int l, int t) {
      
          // showing button when scrolling starts
          if (btnJumpToBottom != null) {
              btnJumpToBottom.setVisibility(View.VISIBLE);
          }
      
          if (btnJumpToTop!= null) {
              btnJumpToTop.setVisibility(View.VISIBLE);
          }
      
      
          if (timer2showJumpButton == null) {
      
              final Runnable r2 = new Runnable() {
      
                  @Override
                  public void run() {
                      if (btnJumpToBottom != null) {
                          btnJumpToBottom.setVisibility(View.GONE);
                      }
                      if (btnJumpToTop!= null) {
                          btnJumpToTop.setVisibility(View.GONE);
                      }
      
                  }
              };
      
              TimerTask timerTask = new TimerTask() {
                  @Override
                  public void run() {
                      if (btnJumpToTop.getVisibility() == View.VISIBLE || btnJumpToBottom.getVisibility() == View.VISIBLE){
                          long currentTimestamp = System.currentTimeMillis();
      
                          if (currentTimestamp - lastScrollEventTimestamp > HIDING_JUMP_BUTTON_ON_SCROLL_DELAY1 ){                        
                              webView.postDelayed(r2, HIDING_JUMP_BUTTON_ON_SCROLL_DELAY);
                          }else{
                              //too soon
                          }
                      }
                  }
              };
      
              try {
                  timer2showJumpButton = new Timer();
                  timer2showJumpButton.schedule(timerTask, 500, 500);
              } catch (IllegalStateException e) {
                  logger.warn(TAG + "/onScrollChanged/" + e.getMessage());
      
              }   
          }
      
          // adding runnable which will hide button back
          long currentTimestamp = System.currentTimeMillis();
      
          lastScrollEventTimestamp = currentTimestamp;
      }
      

      【讨论】:

      • 发现“web.pageDown(true);”在滚动期间工作,但“web.scrollTo(0, scrollTo);”被忽略。
      • 当页面滚动时,您将获得数百个 onScrollChanged 回调,这将分配大量 Timer 对象:) 一种方法是拥有一个计时器/线程,它将以固定间隔运行(约 500 毫秒)。然后,您将在 onScrollChanged 记录上次滚动时间戳,并根据上次滚动时间戳禁用/启用计时器上的按钮。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 2017-12-21
      • 2012-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多