WebView избавляется от двойного увеличения.
Я прочитал много заявок на тему масштабирования в WebViews и не пришел к ответу для моего случая.
Вот мои настройки:
Я использую пользовательский веб-просмотр с такими настройками:
getSettings().setBuiltInZoomControls(false);
getSettings().setSupportZoom(false);
getSettings().setUseWideViewPort(true);
getSettings().setLoadWithOverviewMode(true);
Позвольте мне отметить прямо здесь, что я зависим от OverviewMode, а также от WideViewPort для масштабирования моего WebView.
Я также переопределяю свой OnTouchEvent и делегирую все подходящие события детектору жестов:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) return true;
return super.onTouchEvent(event);
}
Вот его реализация слушателей, которая перехватывает все события doubleTap:
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Do nothing!
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// Do nothing!
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Do nothing!
return true;
}
Также я переопределил эти 2 метода WebView, связанных с масштабированием:
@Override
public boolean zoomIn() {
return true;
}
@Override
public boolean zoomOut() {
return true;
}
Тем не менее, ни одна из этих опций не позволяет увеличивать / уменьшать мой веб-просмотр. Я не нашел опцию, которая отключает этот вид масштабирования, MotionEvent для этого Zoom, кажется, не применим для GestureDetector, и переопределенные методы zoomIn() zoomOut() также не имеют никакого эффекта.
Может ли кто-нибудь помочь мне избежать поведения двойного касания в WebView?
6 ответов
Есть два метода для достижения вашей цели:
Способ 1
Реализовать GestureDetector.OnDoubleTapListener
как это:
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return false; //Nothing
}
@Override
public boolean onDoubleTap(MotionEvent e) {
//Indicates that this implementation has handled the double tap.
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
//Indicates that this implementation has handled the double tap.
return true;
}
и прикрепить его к вашему GestureDetector
как это:
gestureDetector.setOnDoubleTapListener(this);
Способ 2
Вы также можете использовать WebSettings.setUseWideViewPort(false);
и рассчитать размер вашего вида вручную.
Эти методы должны помочь вам достичь не масштабируемых веб-просмотров, которые отображают все.
public int getWindowWidth(Activity activity) {
Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
return width;
}
public int getInitialScale(Activity activity, int websiteWidth) {
return (getWindowWidth(activity) / websiteWidth) * 100;
}
Существует фантастическое решение для вашей проблемы, основанное на Javascript (так что вам придется иметь доступ к коду HTML/JS на удаленной стороне, если это так).
Используя библиотеку FastClick, все, что вам нужно сделать, это добавить файл.js и затем вызвать его:
<script type="application/javascript" src="fastclick.js"></script>
<script language="javascript">
window.addEventListener('load', function() {
FastClick.attach(document.body);
}, false);
</script>
Это избавит от двойного увеличения, и, по-моему, еще есть огромный бонус: все касания получают на 0,3 секунды быстрее, потому что системе больше не нужно ждать двойного нажатия! Проверьте этот пример на Android, чтобы увидеть разницу: Практический пример
Ну, я не знаю, подойдет ли это решение в вашем случае, но это было идеальное решение для моих проектов Webview. Надеюсь, поможет!
PS1: вы должны добавить код выше во всех страницах и фреймах
PS2: масштабирование будет работать нормально
Вам нужно переопределить OnTouchListener в вашем WebView с помощью
wv.setOnTouchListener(this);
и внутри метода onTouch просто проверьте, что если он обнаруживает двойную вкладку, то игнорирует увеличение в веб-просмотре, принудительно возвращая true
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
onTouchEvent(event);
if (doubletab)
return true;
return false;
}
Вы можете увидеть полный код, как это: MainActivity.java
package com.example.testwebview;
import android.os.Bundle;
import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnTouchListener;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.TextView;
public class MainActivity extends Activity implements OnGestureListener, OnTouchListener, GestureDetector.OnDoubleTapListener
{
TextView tv;
WebView wv;
GestureDetector gd;
boolean doubletab = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gd = new GestureDetector(this);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.textView1);
wv = (WebView)findViewById(R.id.webView1);
WebSettings setting = wv.getSettings();
setting.setBuiltInZoomControls(false);
setting.setSupportZoom(false);
setting.setUseWideViewPort(true);
setting.setLoadWithOverviewMode(true);
wv.setOnTouchListener(this);
wv.loadUrl("http://www.sanook.com");
}
@Override
public boolean onDoubleTap(MotionEvent arg0) {
tv.setText("double tap");
doubletab = true;
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent arg0) {
tv.setText("double tap event");
doubletab = true;
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent arg0) {
tv.setText("single tap confirm");
doubletab = false;
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onTouchEvent(MotionEvent me)
{
return gd.onTouchEvent(me);
}
@Override
public boolean onDown(MotionEvent arg0) {
tv.setText("down");
doubletab = false;
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
tv.setText("fling");
doubletab = false;
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
tv.setText("long press");
doubletab = false;
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
tv.setText("scroll");
doubletab = false;
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
tv.setText("show press");
doubletab = false;
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
tv.setText("single tab up");
doubletab = false;
return false;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
onTouchEvent(event);
if (doubletab)
return true;
return false;
}
}
и activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="TextView" />
<WebView
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView1" />
</RelativeLayout>
не забудьте добавить разрешение в manifest.xml
<uses-permission android:name="android.permission.INTERNET" />
Другой подход (единственный, который работал для меня) состоял бы в том, чтобы моделировать отдаленные промежуточные касания между двойными касаниями, чтобы WebView не распознавал их как последующие. Для этой цели можно использовать отрицательные координаты, хотя все, что меньше -1, может замедлить или даже нарушить процесс. Таким образом, нам нужно, по крайней мере, две точки, скажем, (0, -1) и (2*d+1, -1), где d - максимальное расстояние между ответвлениями, чтобы их можно было считать двойным нажатием.
webView.setOnTouchListener(new View.OnTouchListener() {
private long lastUp = -1000;
private float lastDownX = -1000;
private float lastDownY = -1000;
private int dtDistance = 0;
private int dtDistanceSquared = 0;
private long dtTime = 0;
private void performTap(View v, int x, int y, long t) {
MotionEvent e_down = MotionEvent.obtain(t, t, MotionEvent.ACTION_DOWN, x, y, 0);
v.dispatchTouchEvent(e_down);
e_down.recycle();
MotionEvent e_up = MotionEvent.obtain(t, t, MotionEvent.ACTION_UP, x, y, 0);
v.dispatchTouchEvent(e_up);
e_up.recycle();
}
private int getRemoteX(float x) {
return Math.round(x > dtDistance + 0.5 ? 0 : 2 * dtDistance + 1);
}
private boolean inRadius(int x0, int y0, float x1, float y1) {
boolean result = (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) <= dtDistanceSquared;
return result;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getY() >= 0) // Otherwise it's a fake tap we simulated
{
if (dtTime == 0)
{
dtDistance = ViewConfiguration.get(v.getContext()).getScaledDoubleTapSlop(); // Maximum distance between taps for them to be considered double tap
dtDistanceSquared = dtDistance * dtDistance;
dtTime = ViewConfiguration.getDoubleTapTimeout(); // Maximum time elapsed between taps for them to be considered double tap
}
switch (event.getAction())
{
case MotionEvent.ACTION_UP:
lastUp = event.getEventTime();
break;
case MotionEvent.ACTION_DOWN:
long t = event.getEventTime();
if (t - lastUp < dtTime * 4/3) // Very rarely just (t - lastUp <= dtTime) doesn't work
{
int x = getRemoteX(event.getX());
if (inRadius(x, -1, lastDownX, lastDownY))
performTap(v, getRemoteX(lastDownX), -1, t); // Otherwise our fake tap would constitute a double tap with the previous real tap
performTap(v, x, -1, t);
}
lastDownX = event.getX();
lastDownY = event.getY();
break;
}
}
return false;
}
});
Если возможно, замените статический метатег в своем HTML:
<script>
var meta = document.createElement("meta");
meta.setAttribute('name','viewport');
meta.setAttribute('content','width=device-width, user-scalable=no');
document.getElementsByTagName('head')[0].appendChild(meta);
</script>
Кроме того, вы можете использовать хороший скрипт: FastClick
Он не будет ждать событий касания, так что это быстрее.
<script type="application/javascript" src="fastclick.js"></script>
<script language="javascript">
window.addEventListener('load', function() {
FastClick.attach(document.body);
}, false);
</script>
Затем установите слушателя двойного касания на ваш детектор жестов. (в пользовательском WebView)
gestureDetector.setOnDoubleTapListener(new OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed( MotionEvent e ) {
return false;
}
@Override
public boolean onDoubleTapEvent( MotionEvent e ) {
return true;
}
@Override
public boolean onDoubleTap( MotionEvent e ) {
return true;
}
});
Переопределите метод onTouchEvent (в пользовательском WebView):
@Override
public boolean onTouchEvent( MotionEvent event ) {
boolean gestureHandled = gestureDetector.onTouchEvent(event);
int actionMask = event.getActionMasked() & MotionEvent.ACTION_MASK;
int index = ( event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointId = event.getPointerId(index);
// ignore move events
if (actionMask == MotionEvent.ACTION_MOVE) {
return super.onTouchEvent(event);
}
// cancel detected double taps
if (gestureDetector.onTouchEvent(event)) {
event.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(event);
return true;
}
// if you want to ignore multi touch events/taps
if (pointId != 0) {
System.out.println("KEY multiple points detected");
return true;
}
// use single taps
if (event.getAction() == MotionEvent.ACTION_UP) {
event.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(event);
event.setAction(MotionEvent.ACTION_DOWN);
super.onTouchEvent(event);
event.setAction(MotionEvent.ACTION_UP);
return true;
}
return super.onTouchEvent(event);
}
Попробуйте сделать возвращаемые значения onDoubleTapEvent onDoubleTap как ложные....
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Do nothing!
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// Do nothing!
return false;
}