سؤال

أنا أستخدم طريقة onScroll الخاصة بـ GestureDetector.SimpleOnGestureListener لتمرير صورة نقطية كبيرة على اللوحة القماشية.عندما ينتهي التمرير، أريد إعادة رسم الصورة النقطية في حالة رغبة المستخدم في التمرير أكثر ...من حافة الصورة النقطية، لكن لا يمكنني رؤية كيفية اكتشاف وقت انتهاء التمرير (رفع المستخدم إصبعه من الشاشة).

يبدو دائمًا أن e2.getAction() يُرجع القيمة 2، لذا لا يوجد أي مساعدة.يبدو أن e2.getPressure يُرجع قيمًا ثابتة إلى حد ما (حوالي 0.25) حتى استدعاء onScroll النهائي عندما يبدو أن الضغط ينخفض ​​إلى حوالي 0.13.أفترض أنني أستطيع اكتشاف هذا الانخفاض في الضغط، لكن هذا لن يكون مضمونًا على الإطلاق.

يجب أن تكون هناك طريقة أفضل:يمكن لأي شخص أن يساعد، من فضلك؟

هل كانت مفيدة؟

المحلول

هنا كيف قمت بحل المشكلة.أتمنى أن يساعدك هذا.

// declare class member variables
private GestureDetector mGestureDetector;
private OnTouchListener mGestureListener;
private boolean mIsScrolling = false;


public void initGestureDetection() {
        // Gesture detection
    mGestureDetector = new GestureDetector(new SimpleOnGestureListener() {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            handleDoubleTap(e);
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            handleSingleTap(e);
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // i'm only scrolling along the X axis
            mIsScrolling = true;                
            handleScroll(Math.round((e2.getX() - e1.getX())));
            return true;
        }

        @Override
        /**
         * Don't know why but we need to intercept this guy and return true so that the other gestures are handled.
         * https://code.google.com/p/android/issues/detail?id=8233
         */
        public boolean onDown(MotionEvent e) {
            Log.d("GestureDetector --> onDown");
            return true;
        }
    });

    mGestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {

            if (mGestureDetector.onTouchEvent(event)) {
                return true;
            }

            if(event.getAction() == MotionEvent.ACTION_UP) {
                if(mIsScrolling ) {
                    Log.d("OnTouchListener --> onTouch ACTION_UP");
                    mIsScrolling  = false;
                    handleScrollFinished();
                };
            }

            return false;
        }
    };

    // attach the OnTouchListener to the image view
    mImageView.setOnTouchListener(mGestureListener);
}

نصائح أخرى

يجب عليك إلقاء نظرة على http://developer.android.com/reference/android/widget/Scroller.html.يمكن أن يكون هذا مفيدًا بشكل خاص (مرتبة حسب الصلة):

isFinished();
computeScrollOffset();
getFinalY(); getFinalX(); and getCurrY() getCurrX()
getDuration()

هذا يعني أنه يجب عليك إنشاء Scroller.

إذا كنت تريد استخدام اللمس، فيمكنك أيضًا استخدام GestureDetector وتحديد التمرير القماشي الخاص بك.النموذج التالي يقوم بإنشاء ScrollableImageView ومن أجل استخدامه عليك تحديد قياسات صورتك.يمكنك تحديد نطاق التمرير الخاص بك وبعد الانتهاء من التمرير، تتم إعادة رسم الصورة.

http://www.anddev.org/viewtopic.php?p=31487#31487

اعتمادًا على الكود الخاص بك، يجب أن تفكر في إبطال (int l, int t, int r, int b);للبطلان.

SimpleOnGestureListener.onFling() 

يبدو أنه يحدث عندما ينتهي التمرير (أي.(يترك المستخدم إصبعه)، وهذا ما أستخدمه وهو يعمل بشكل رائع بالنسبة لي.

بالعودة إلى هذا بعد بضعة أشهر، اتبعت الآن مسارًا مختلفًا:استخدام معالج (كما هو الحال في نموذج Android Snake) لإرسال رسالة إلى التطبيق كل 125 مللي ثانية والتي تطالبه بالتحقق مما إذا كان قد تم بدء التمرير وما إذا كان قد انقضى أكثر من 100 مللي ثانية منذ حدث التمرير الأخير.

يبدو أن هذا يعمل بشكل جيد، ولكن إذا كان بإمكان أي شخص رؤية أي عيوب أو تحسينات محتملة، سأكون ممتنًا لسماعها.

الكود ذو الصلة موجود في فئة MyView:

public class MyView extends android.view.View {

...

private long timeCheckInterval = 125; // milliseconds
private long scrollEndInterval = 100;
public long latestScrollEventTime;
public boolean scrollInProgress = false;

public MyView(Context context) {
    super(context);
}

private timeCheckHandler mTimeCheckHandler = new timeCheckHandler();

class timeCheckHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
        long now = System.currentTimeMillis();
        if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval)) {
                    scrollInProgress = false;

// انتهى التمرير، لذا أدخل الكود هنا

// الذي يستدعي طريقة doDrawing ().

// لإعادة رسم الصورة النقطية وإعادة توسيطها حيث انتهى التمرير

                    [ layout or view ].invalidate();
        }
        this.sleep(timeCheckInterval);
        }

        public void sleep(long delayMillis) {
            this.removeMessages(0);
            sendMessageDelayed(obtainMessage(0), delayMillis);
            }
    }
}

@Override protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

// رمز لرسم صورة نقطية كبيرة مخزن مؤقت على قماش العرض // الموقع لأخذ أي تمرير قيد التقدم

}

public void doDrawing() {

// رمز للقيام برسم مفصل (ويستغرق وقتًا طويلاً) // على صورة نقطية كبيرة عازلة

.

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// بقية فئة MyView

}

وفي فئة MyGestureDetector

public class MyGestureDetector extends SimpleOnGestureListener {

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {

    [MyView].scrollInProgress = true;
        long now = System.currentTimeMillis();  
    [MyView].latestScrollEventTime =now;

    [MyView].scrollX += (int) distanceX;
    [MyView].scrollY += (int) distanceY;

// تتسبب التعليمات التالية في أن يتم استدعاء طريقة Ondraw الخاصة بالمنظر // والتي ترسم صورة نقطية عازلة على الشاشة // تحولت لمراعاة التمرير

    [MyView].invalidate();

}

// بقية فئة MyGestureDetector

}

كنت أبحث في هذه القضية نفسها.رأيت Akos Cz يجيب على سؤالك.لقد قمت بإنشاء شيء مشابه، ولكن مع الإصدار الخاص بي لاحظت أنه يعمل فقط مع التمرير العادي - أي التمرير الذي لا يولد قذفًا.ولكن إذا تم إنشاء قذف - بغض النظر عما إذا كنت قد قمت بمعالجة قذف أم لا، فلن يكتشف "ACTION_UP" في "onTouchEvent".الآن ربما كان هذا مجرد شيء يتعلق بتنفيذي، ولكن إذا كان الأمر كذلك، فلن أتمكن من معرفة السبب.

بعد مزيد من التحقيق، لاحظت أنه أثناء القذف، تم تمرير "ACTION_UP" إلى "onFling" في "e2" في كل مرة.لذلك أدركت أن هذا هو سبب عدم التعامل معه في "onTouchEvent" في تلك الحالات.

ولجعل الأمر يعمل بالنسبة لي، كان علي فقط استدعاء طريقة للتعامل مع "ACTION_UP" في "onFling" ثم عملت مع كلا النوعين من التمرير.فيما يلي الخطوات الدقيقة التي اتخذتها للتنفيذ في تطبيقي:

- تهيئة منطقية "التمرير بالإيماءة" إلى "خطأ" في المُنشئ.

-لقد قمت بتعيينه على "صحيح" في "onScroll"

-تم إنشاء طريقة للتعامل مع الحدث "ACTION_UP".داخل هذا الحدث، قمت بإعادة تعيين "gestureSCrolling" إلى "خطأ" ثم قمت ببقية المعالجة التي كنت بحاجة إلى القيام بها.

-في "onTouchEvent"، إذا تم اكتشاف "ACTION_UP" وكان "gestureScrolling" = صحيحًا، فقد قمت باستدعاء طريقتي للتعامل مع "ACTION_UP"

- والجزء الذي فعلته كان مختلفًا:لقد قمت أيضًا باستدعاء طريقتي للتعامل مع "ACTION_UP" داخل "onFling".

أنا متأكد من أن الوقت قد فات بالنسبة لك، ولكن يبدو أنني وجدت الحل الصحيح لسؤالك الأصلي وليس من الضروري وجود النية.

إذا كنت تستخدم كائن Scroller/OverScroller للتمرير، فيجب عليك التحقق من القيمة المرجعة من الوظيفة التالية.

public boolean computeScrollOffset() 

يتمتع

هارفيندر

هذا هو ما نجح بالنسبة لي.

لقد قمت بإثراء الموجود GestureDetector.OnGestureListener مع onFingerUp() طريقة.يقوم هذا المستمع بكل شيء باعتباره GestureDetector المدمج ويمكنه أيضًا الاستماع إلى حدث رفع الإصبع (إنه ليس onFling() حيث يتم استدعاؤه فقط عندما يتم رفع الإصبع لأعلى مع إجراء تمرير سريع).

import android.content.Context;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class FingerUpGestureDetector extends GestureDetector {
    FingerUpGestureDetector.OnGestureListener fListener;
    public FingerUpGestureDetector(Context context, OnGestureListener listener) {
        super(context, listener);
        fListener = listener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, OnGestureListener fListener) {
        super(context, listener);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, OnGestureListener fListener) {
        super(context, listener, handler);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused, OnGestureListener fListener) {
        super(context, listener, handler, unused);
        this.fListener = fListener;
    }

    public interface OnGestureListener extends GestureDetector.OnGestureListener {
        boolean onFingerUp(MotionEvent e);
    }

    public static class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements FingerUpGestureDetector.OnGestureListener {
        @Override
        public boolean onFingerUp(MotionEvent e) {
            return false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (super.onTouchEvent(ev)) return true;
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            return fListener.onFingerUp(ev);
        }
        return false;
    }
}

لم أفعل هذا بنفسي ولكن بالنظر إلى onTouch() تحصل دائمًا على التسلسل 0<2>1، لذا يجب أن تكون النهاية 1 لرفع الإصبع.

لا أعرف نظام Android، ولكن بالنظر إلى الوثائق يبدو أن روب على حق: Android ACTION_UP ثابت حاول التحقق من ACTION_UP من getAction()؟

يحرر:ماذا يظهر e1.getAction()؟هل يُرجع ACTION_UP أبدًا؟تشير الوثائق إلى أنها تحمل حدث الانخفاض الأولي، لذلك ربما ستُعلم أيضًا عندما يرتفع المؤشر

يحرر:هناك شيئان آخران فقط يمكنني التفكير فيهما.هل تعود كاذبة في أي وقت؟قد يمنع ذلك ACTION_UP

الشيء الآخر الوحيد الذي سأحاوله هو إنشاء حدث منفصل، ربما onDown، وتعيين علامة داخل onScroll مثل isScrolling.عندما يتم إعطاء ACTION_UP إلى onDown ويتم تعيين isScrolling، فيمكنك القيام بما تريد وإعادة تعيين isScrolling إلى false.وهذا يعني أنه بافتراض أن onDown يتم استدعاؤه مع onScroll، فسيقوم getAction بإرجاع ACTION_UP أثناء onDown

لم أحاول/استخدم هذا ولكن فكرة للنهج:

قم بإيقاف/مقاطعة إعادة رسم اللوحة القماشية في كل حدث تمرير، انتظر ثانية واحدة ثم ابدأ في إعادة رسم اللوحة القماشية في كل تمريرة.

سيؤدي هذا إلى إجراء إعادة الرسم فقط عند نهاية التمرير حيث أن التمرير الأخير فقط هو الذي سيتم دون انقطاع حتى تكتمل عملية إعادة الرسم.

نأمل أن تساعدك هذه الفكرة :)

مقتطف من حدث onScroll من GestureListener API: نص الرابط

المجردة العامة المجردة المنطقية onscroll (MotionEvent E1 ، MotionEvent E2 ، Float quatex ، float quatery) منذ:API المستوى 1

إرجاع * صحيح إذا تم استهلاك الحدث ، وإلا كاذبة

ربما بمجرد استهلاك الحدث، يكون الإجراء قد انتهى وقام المستخدم برفع إصبعه عن الشاشة أو على الأقل أنهى إجراء onScroll هذا

يمكنك بعد ذلك استخدام هذا في عبارة IF للبحث عن == true ثم البدء بالإجراء التالي.

أعتقد أن هذا سيعمل حسب حاجتك

protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
        boolean result = super.onScroll(e1, e2, distanceX, distanceY);

        if(!result){
            //Do what you need to do when the scrolling stop here
        }

        return result;
    }

}

محاولتي لإضافة وظائف إضافية لكشف الإيماءات.آمل أن يساعد شخص ما في استغلال وقته بشكل أفضل ...

https://Gist.github.com/WildOrangutan/043807ddbd68978179b7cea3b53c71e8

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top