【问题标题】:Google Tv app-How to implement of MOUSE pointer on WEBVIEW navigation controlled from D-pad?Google Tv 应用程序-如何在 D-pad 控制的 WEBVIEW 导航上实现鼠标指针?
【发布时间】:2018-02-05 09:58:49
【问题描述】:

为 Android TV 实施基于 Webview 的应用程序,没有指向视频页面的网站链接。网页是桌面,使用方向键导航非常困难。我想实现由 D-Pad 控制的鼠标光标类型的导航。对可用示例源代码的任何帮助都会有所帮助。

【问题讨论】:

  • 请问你找到方法了吗?

标签: webview d-pad


【解决方案1】:

在这里尝试做同样的事情。


基本方法:

  • 创建用于绘制、移动和动画光标的自定义视图
  • 在框架布局中,将此自定义光标视图添加到 Web 视图的顶部
  • 当用户单击(键:DPAD 中心)时,通过模拟触摸事件模拟对光标位置的单击
  • 当光标位于边缘时,按下相应的按钮滚动 WebView

这样做时,焦点处理有点像 PITA:

当它有焦点时,webview 会做各种奇怪的事情(滚动、突出显示,...)。所以我试着让我的光标视图聚焦。工作得非常好,除非点击文本输入字段 -> 如果 WebView 没有获得焦点,键盘将不会显示/工作。

因此,使用 getHitTestResult() 我们可以确定我们的点击是否会点击输入字段并使 WebView 之前获得焦点。这很好用,但我还没有找到一种可靠的方法来在用户完成输入文本时将焦点交回我的光标视图。

我尝试过的一件事是挂钩 IME 连接,但我无法让这种方法足够稳定以在公共应用程序中使用它。

【讨论】:

    【解决方案2】:

    通过创建自定义指针布局在 android tv webview 中启用光标指针

    public class CursorLayout extends FrameLayout {
    public static final int CURSOR_DISAPPEAR_TIMEOUT = 5000;
    public static int CURSOR_RADIUS = 0;
    public static float CURSOR_STROKE_WIDTH = 0.0f;
    public static float MAX_CURSOR_SPEED = 0.0f;
    public static int SCROLL_START_PADDING = 100;
    public static final int UNCHANGED = -100;
    public int EFFECT_DIAMETER;
    public int EFFECT_RADIUS;
    private Callback callback;
    /* access modifiers changed from: private */
    public Point cursorDirection = new Point(0, 0);
    /* access modifiers changed from: private */
    public Runnable cursorHideRunnable = new Runnable() {
        public void run() {
            CursorLayout.this.invalidate();
        }
    };
    /* access modifiers changed from: private */
    public PointF cursorPosition = new PointF(0.0f, 0.0f);
    /* access modifiers changed from: private */
    public PointF cursorSpeed = new PointF(0.0f, 0.0f);
    private Runnable cursorUpdateRunnable = new Runnable() {
        public void run() {
            if (CursorLayout.this.getHandler() != null) {
                CursorLayout.this.getHandler().removeCallbacks(CursorLayout.this.cursorHideRunnable);
            }
            long currentTimeMillis = System.currentTimeMillis();
            long access$100 = currentTimeMillis - CursorLayout.this.lastCursorUpdate;
            CursorLayout.this.lastCursorUpdate = currentTimeMillis;
            float f = ((float) access$100) * 0.05f;
            PointF access$200 = CursorLayout.this.cursorSpeed;
            CursorLayout cursorLayout = CursorLayout.this;
            float f2 = cursorLayout.cursorSpeed.x;
            CursorLayout cursorLayout2 = CursorLayout.this;
            float access$400 = cursorLayout.bound(f2 + (cursorLayout2.bound((float) cursorLayout2.cursorDirection.x, 1.0f) * f), CursorLayout.MAX_CURSOR_SPEED);
            CursorLayout cursorLayout3 = CursorLayout.this;
            float f3 = cursorLayout3.cursorSpeed.y;
            CursorLayout cursorLayout4 = CursorLayout.this;
            access$200.set(access$400, cursorLayout3.bound(f3 + (cursorLayout4.bound((float) cursorLayout4.cursorDirection.y, 1.0f) * f), CursorLayout.MAX_CURSOR_SPEED));
            if (Math.abs(CursorLayout.this.cursorSpeed.x) < 0.1f) {
                CursorLayout.this.cursorSpeed.x = 0.0f;
            }
            if (Math.abs(CursorLayout.this.cursorSpeed.y) < 0.1f) {
                CursorLayout.this.cursorSpeed.y = 0.0f;
            }
            if (CursorLayout.this.cursorDirection.x == 0 && CursorLayout.this.cursorDirection.y == 0 && CursorLayout.this.cursorSpeed.x == 0.0f && CursorLayout.this.cursorSpeed.y == 0.0f) {
                if (CursorLayout.this.getHandler() != null) {
                    CursorLayout.this.getHandler().postDelayed(CursorLayout.this.cursorHideRunnable, 5000);
                }
                return;
            }
            CursorLayout.this.tmpPointF.set(CursorLayout.this.cursorPosition);
            CursorLayout.this.cursorPosition.offset(CursorLayout.this.cursorSpeed.x, CursorLayout.this.cursorSpeed.y);
            Log.d("cursor1234_xxxx", String.valueOf(CursorLayout.this.cursorPosition.x));
            Log.d("cursor1234_yyyy", String.valueOf(CursorLayout.this.cursorPosition.y));
            if (CursorLayout.this.cursorPosition.x < 0.0f) {
                CursorLayout.this.cursorPosition.x = 0.0f;
            } else if (CursorLayout.this.cursorPosition.x > ((float) (CursorLayout.this.getWidth() - 1))) {
                CursorLayout.this.cursorPosition.x = (float) (CursorLayout.this.getWidth() - 1);
            }
            if (CursorLayout.this.cursorPosition.y < 0.0f) {
                CursorLayout.this.cursorPosition.y = 0.0f;
            } else if (CursorLayout.this.cursorPosition.y > ((float) (CursorLayout.this.getHeight() - 1))) {
                CursorLayout.this.cursorPosition.y = (float) (CursorLayout.this.getHeight() - 1);
            }
            if (!CursorLayout.this.tmpPointF.equals(CursorLayout.this.cursorPosition) && CursorLayout.this.dpadCenterPressed) {
                CursorLayout cursorLayout5 = CursorLayout.this;
                cursorLayout5.dispatchMotionEvent(cursorLayout5.cursorPosition.x, CursorLayout.this.cursorPosition.y, 2);
            }
            View childAt = CursorLayout.this.getChildAt(0);
            if (childAt != null) {
                if (CursorLayout.this.cursorPosition.y > ((float) (CursorLayout.this.getHeight() - CursorLayout.SCROLL_START_PADDING))) {
                    if (CursorLayout.this.cursorSpeed.y > 0.0f && childAt.canScrollVertically((int) CursorLayout.this.cursorSpeed.y)) {
                        childAt.scrollTo(childAt.getScrollX(), childAt.getScrollY() + ((int) CursorLayout.this.cursorSpeed.y));
                    }
                } else if (CursorLayout.this.cursorPosition.y < ((float) CursorLayout.SCROLL_START_PADDING) && CursorLayout.this.cursorSpeed.y < 0.0f && childAt.canScrollVertically((int) CursorLayout.this.cursorSpeed.y)) {
                    childAt.scrollTo(childAt.getScrollX(), childAt.getScrollY() + ((int) CursorLayout.this.cursorSpeed.y));
                }
                if (CursorLayout.this.cursorPosition.x > ((float) (CursorLayout.this.getWidth() - CursorLayout.SCROLL_START_PADDING))) {
                    if (CursorLayout.this.cursorSpeed.x > 0.0f && childAt.canScrollHorizontally((int) CursorLayout.this.cursorSpeed.x)) {
                        childAt.scrollTo(childAt.getScrollX() + ((int) CursorLayout.this.cursorSpeed.x), childAt.getScrollY());
                    }
                } else if (CursorLayout.this.cursorPosition.x < ((float) CursorLayout.SCROLL_START_PADDING) && CursorLayout.this.cursorSpeed.x < 0.0f && childAt.canScrollHorizontally((int) CursorLayout.this.cursorSpeed.x)) {
                    childAt.scrollTo(childAt.getScrollX() + ((int) CursorLayout.this.cursorSpeed.x), childAt.getScrollY());
                }
            }
            CursorLayout.this.invalidate();
            if (CursorLayout.this.getHandler() != null) {
                CursorLayout.this.getHandler().post(this);
            }
        }
    };
    /* access modifiers changed from: private */
    public boolean dpadCenterPressed = false;
    /* access modifiers changed from: private */
    public long lastCursorUpdate = System.currentTimeMillis();
    private Paint paint = new Paint();
    PointF tmpPointF = new PointF();
    
    public interface Callback {
        void onUserInteraction();
    }
    
    /* access modifiers changed from: private */
    public float bound(float f, float f2) {
        if (f > f2) {
            return f2;
        }
        float f3 = -f2;
        return f < f3 ? f3 : f;
    }
    
    public CursorLayout(Context context) {
        super(context);
        init();
    }
    
    public CursorLayout(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        init();
    }
    
    private void init() {
        if (!isInEditMode()) {
            this.paint.setAntiAlias(true);
            setWillNotDraw(false);
            Display defaultDisplay = ((WindowManager) getContext().getSystemService(getContext().WINDOW_SERVICE)).getDefaultDisplay();
            Point point = new Point();
            defaultDisplay.getSize(point);
            this.EFFECT_RADIUS = point.x / 20;
            this.EFFECT_DIAMETER = this.EFFECT_RADIUS * 2;
            CURSOR_STROKE_WIDTH = (float) (point.x / 400);
            CURSOR_RADIUS = point.x / 110;
            MAX_CURSOR_SPEED = (float) (point.x / 25);
            SCROLL_START_PADDING = point.x / 15;
        }
    }
    
    public void setCallback(Callback callback2) {
        this.callback = callback2;
    }
    
    public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
        Callback callback2 = this.callback;
        if (callback2 != null) {
            callback2.onUserInteraction();
        }
        return super.onInterceptTouchEvent(motionEvent);
    }
    
    /* access modifiers changed from: protected */
    public void onSizeChanged(int i, int i2, int i3, int i4) {
        super.onSizeChanged(i, i2, i3, i4);
        UtilMethods.LogMethod("cursorView123_", "onSizeChanged");
        if (!isInEditMode()) {
            this.cursorPosition.set(((float) i) / 2.0f, ((float) i2) / 2.0f);
            if (getHandler() != null) {
                getHandler().postDelayed(this.cursorHideRunnable, 5000);
            }
        }
    }
    
    public boolean dispatchKeyEvent(KeyEvent keyEvent) {
        UtilMethods.LogMethod("cursorView123_", "dispatchKeyEvent");
        Callback callback2 = this.callback;
        if (callback2 != null) {
            callback2.onUserInteraction();
        }
        int keyCode = keyEvent.getKeyCode();
        if (!(keyCode == 66 || keyCode == 160)) {
            switch (keyCode) {
                case 19:
                    if (keyEvent.getAction() == 0) {
                        if (this.cursorPosition.y <= 0.0f) {
                            return super.dispatchKeyEvent(keyEvent);
                        }
                        handleDirectionKeyEvent(keyEvent, -100, -1, true);
                    } else if (keyEvent.getAction() == 1) {
                        handleDirectionKeyEvent(keyEvent, -100, 0, false);
                    }
                    return true;
                case 20:
                    if (keyEvent.getAction() == 0) {
                        if (this.cursorPosition.y >= ((float) getHeight())) {
                            return super.dispatchKeyEvent(keyEvent);
                        }
                        handleDirectionKeyEvent(keyEvent, -100, 1, true);
                    } else if (keyEvent.getAction() == 1) {
                        handleDirectionKeyEvent(keyEvent, -100, 0, false);
                    }
                    return true;
                case 21:
                    if (keyEvent.getAction() == 0) {
                        if (this.cursorPosition.x <= 0.0f) {
                            return super.dispatchKeyEvent(keyEvent);
                        }
                        handleDirectionKeyEvent(keyEvent, -1, -100, true);
                    } else if (keyEvent.getAction() == 1) {
                        handleDirectionKeyEvent(keyEvent, 0, -100, false);
                    }
                    return true;
                case 22:
                    if (keyEvent.getAction() == 0) {
                        if (this.cursorPosition.x >= ((float) getWidth())) {
                            return super.dispatchKeyEvent(keyEvent);
                        }
                        handleDirectionKeyEvent(keyEvent, 1, -100, true);
                    } else if (keyEvent.getAction() == 1) {
                        handleDirectionKeyEvent(keyEvent, 0, -100, false);
                    }
                    return true;
                case 23:
                    break;
                default:
                    switch (keyCode) {
                        case 268:
                            if (keyEvent.getAction() == 0) {
                                handleDirectionKeyEvent(keyEvent, -1, -1, true);
                            } else if (keyEvent.getAction() == 1) {
                                handleDirectionKeyEvent(keyEvent, 0, 0, false);
                            }
                            return true;
                        case 269:
                            if (keyEvent.getAction() == 0) {
                                handleDirectionKeyEvent(keyEvent, -1, 1, true);
                            } else if (keyEvent.getAction() == 1) {
                                handleDirectionKeyEvent(keyEvent, 0, 0, false);
                            }
                            return true;
                        case 270:
                            if (keyEvent.getAction() == 0) {
                                handleDirectionKeyEvent(keyEvent, 1, -1, true);
                            } else if (keyEvent.getAction() == 1) {
                                handleDirectionKeyEvent(keyEvent, 0, 0, false);
                            }
                            return true;
                        case 271:
                            if (keyEvent.getAction() == 0) {
                                handleDirectionKeyEvent(keyEvent, 1, 1, true);
                            } else if (keyEvent.getAction() == 1) {
                                handleDirectionKeyEvent(keyEvent, 0, 0, false);
                            }
                            return true;
                    }
            }
        }
        if (!isCursorDissappear()) {
            if (keyEvent.getAction() == 0 && !getKeyDispatcherState().isTracking(keyEvent)) {
                getKeyDispatcherState().startTracking(keyEvent, this);
                this.dpadCenterPressed = true;
                dispatchMotionEvent(this.cursorPosition.x, this.cursorPosition.y, 0);
            } else if (keyEvent.getAction() == 1) {
                getKeyDispatcherState().handleUpEvent(keyEvent);
                dispatchMotionEvent(this.cursorPosition.x, this.cursorPosition.y, 1);
                this.dpadCenterPressed = false;
            }
            return true;
        }
        return super.dispatchKeyEvent(keyEvent);
    }
    
    /* access modifiers changed from: private */
    public void dispatchMotionEvent(float f, float f2, int i) {
        UtilMethods.LogMethod("cursorView123_", "dispatchMotionEvent");
        long uptimeMillis = SystemClock.uptimeMillis();
        long uptimeMillis2 = SystemClock.uptimeMillis();
        PointerProperties pointerProperties = new PointerProperties();
        pointerProperties.id = 0;
        pointerProperties.toolType = 1;
        PointerProperties[] pointerPropertiesArr = {pointerProperties};
        PointerCoords pointerCoords = new PointerCoords();
        pointerCoords.x = f;
        pointerCoords.y = f2;
        pointerCoords.pressure = 1.0f;
        pointerCoords.size = 1.0f;
        dispatchTouchEvent(MotionEvent.obtain(uptimeMillis, uptimeMillis2, i, 1, pointerPropertiesArr, new PointerCoords[]{pointerCoords}, 0, 0, 1.0f, 1.0f, 0, 0, 0, 0));
    }
    
    private void handleDirectionKeyEvent(KeyEvent keyEvent, int i, int i2, boolean z) {
        this.lastCursorUpdate = System.currentTimeMillis();
        if (!z) {
            getKeyDispatcherState().handleUpEvent(keyEvent);
            this.cursorSpeed.set(0.0f, 0.0f);
        } else if (!getKeyDispatcherState().isTracking(keyEvent)) {
            Handler handler = getHandler();
            handler.removeCallbacks(this.cursorUpdateRunnable);
            handler.post(this.cursorUpdateRunnable);
            getKeyDispatcherState().startTracking(keyEvent, this);
        } else {
            return;
        }
        Point point = this.cursorDirection;
        if (i == -100) {
            i = point.x;
        }
        if (i2 == -100) {
            i2 = this.cursorDirection.y;
        }
        point.set(i, i2);
    }
    
    /* access modifiers changed from: protected */
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        UtilMethods.LogMethod("cursorView123_", "dispatchDraw");
        if (!isInEditMode() && !isCursorDissappear()) {
            float f = this.cursorPosition.x;
            float f2 = this.cursorPosition.y;
            this.paint.setColor(Color.argb(128, 255, 255, 255));
            this.paint.setStyle(Style.FILL);
            canvas.drawCircle(f, f2, (float) CURSOR_RADIUS, this.paint);
            this.paint.setColor(-7829368);
            this.paint.setStrokeWidth(CURSOR_STROKE_WIDTH);
            this.paint.setStyle(Style.STROKE);
            canvas.drawCircle(f, f2, (float) CURSOR_RADIUS, this.paint);
        }
    }
    
    private boolean isCursorDissappear() {
        return System.currentTimeMillis() - this.lastCursorUpdate > 5000;
    }
    
    /* access modifiers changed from: protected */
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }}
    

    然后将 webview 放在 XML 中的自定义光标布局中

    <com.example.webviewtvapp.CursorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/cursorLayout">
    
        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </com.example.webviewtvapp.CursorLayout>
    

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 link-only-answers
    猜你喜欢
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 2020-12-06
    • 2010-11-16
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多