টাচলিস্টেনার এবং ক্লিকলিস্টার সহ বোতামটি হাইলাইট অবস্থায় রেখে গেছে


10

নিম্নলিখিতগুলি করার পরে আমার বোতামটি হাইলাইট অবস্থায় থাকতে সমস্যা হচ্ছে:

public class MainActivity extends AppCompatActivity {

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("Test", "calling onClick");
            }
        });
        button.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: {
                        v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                        v.invalidate();
                        break;
                    }
                    case MotionEvent.ACTION_UP: {
                        v.getBackground().clearColorFilter();
                        v.invalidate();
                        v.performClick();
                        Log.d("Test", "Performing click");
                        return true;
                    }
                }
                return false;
            }
        });

    }
}

উপরের কোডটি সম্পর্কিত, এটি ব্যবহার করার সময়, আমি প্রত্যাশা করছি বোতামটি ক্লিকটি টাচ দ্বারা পরিচালিত হবে এবং "সত্য" ফিরিয়ে হ্যান্ডলিং টাচলাইস্টেনারে থামানো উচিত।

তবে এই ঘটনাটি নয়। ক্লিক করার পরেও বোতামটি হাইলাইট অবস্থায় থাকে।

যা পাই তা হ'ল:

Test - calling onClick
Test - Performing click

অন্যদিকে, যদি আমি নিম্নলিখিত কোডটি ব্যবহার করি তবে বোতামটি ক্লিক করা হয়, একই প্রিন্টগুলি হয়, তবে বোতামটি হাইলাইট অবস্থায় আটকে যায় না:

public class MainActivity extends AppCompatActivity {

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("Test", "calling onClick");
            }
        });
        button.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: {
                        v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                        v.invalidate();
                        break;
                    }
                    case MotionEvent.ACTION_UP: {
                        v.getBackground().clearColorFilter();
                        v.invalidate();
                        // v.performClick();
                        Log.d("Test", "Performing click");
                        return false;
                    }
                }
                return false;
            }
        });

    }
}

টাচ ইভেন্টে প্রতিক্রিয়াশীল চেইন কী তা নিয়ে আমি কিছুটা বিভ্রান্ত। আমার অনুমান যে এটি:

1) টাচলিস্টনার

2) ক্লিকলিস্টার

3) প্যারেন্টভিউ

কেউ কি এটিও নিশ্চিত করতে পারেন?


আপনি আসলে যা করতে চান, এটি কি স্পর্শ করে পরিচালনা করছে বা কেবল প্রেসে রঙ পরিবর্তন করছে?
হায়দার সালেম

আমি স্পর্শে কিছু যুক্তি চালাতে চাই এবং তারপরে পারফরম্যান্স ক্লিক ক্লিক করুন এবং এটির জন্য বোতামটির রঙ পরিবর্তন না করা।
হোয়াইটবিয়ার

@ হোয়াইটবিয়ার দয়া করে নীচের উত্তরটি দেখুন। আমি আরও তথ্য যুক্ত করতে পারেন।
GensaGames

এটি আপনাকে স্পর্শ ইভেন্টগুলির প্রবাহ বুঝতে সাহায্য করতে পারে। আপনি কী ঘটতে চান তা পরিষ্কার নয়। আপনি কি একটি ক্লিক হ্যান্ডলার চান এবং সম্পাদনা ক্লিক করতে চান? আপনি কি চান যে বাটনটি তার প্রাথমিক রঙ থেকে শুরু করে রঙিন ফিল্টার দ্বারা সেট করা রাজ্যে যেতে হবে আবার তার প্রাথমিক রঙে ফিরে যেতে?
চেটিক্যাম্প

আমার অর্থ কী তা বোঝাতে দিন। আমার বোতামে একটি টাচলিস্টনার এবং একটি ক্লিকলিস্টার রয়েছে। স্পর্শটি অগ্রাধিকার অনুসারে ক্লিকের পূর্ববর্তী এবং যদি ইভেন্টটি পরিচালনা করে তবে সত্য ফিরে আসে, যার অর্থ এটি অন্য কারওর হাতল করা উচিত নয়। আমি স্পর্শের মাধ্যমে ঠিক যা করছি, ক্লিকটি পরিচালনা করে এবং সত্যে ফিরে আসছি, তবুও বোতামটি হাইলাইট থাকে যদিও এটি অনক্লিক শ্রোতা বলা হয় এবং প্রবাহটি সঠিকভাবে সম্পন্ন হয়।
হোয়াইটবিয়ার

উত্তর:


10

এই ধরনের কাস্টমাইজেশনের কোনও প্রোগ্রামিকরূপে পরিবর্তনগুলির প্রয়োজন নেই। আপনি কেবল xmlফাইলগুলিতে এটি করতে পারেন । প্রথমত, setOnTouchListenerআপনি যে পদ্ধতিটি onCreateপুরোপুরি সরবরাহ করেন তা মুছুন । এরপরে, res/colorনিম্নলিখিতগুলির মতো ডিরেক্টরিতে একটি নির্বাচক রঙ নির্ধারণ করুন । (যদি ডিরেক্টরিটি বিদ্যমান না থাকে তবে এটি তৈরি করুন)

মাঝামাঝি / রং / button_tint_color.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#e0f47521" android:state_pressed="true" />
    <item android:color="?attr/colorButtonNormal" android:state_pressed="false" />
</selector>

এখন, এটি বোতামের app:backgroundTintবৈশিষ্ট্যে সেট করুন :

<androidx.appcompat.widget.AppCompatButton
    android:id="@+id/mybutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"
    app:backgroundTint="@color/button_tint_color" />


ভিজ্যুয়াল ফলাফল:

এখানে চিত্র বর্ণনা লিখুন



সম্পাদনা: (স্পর্শ ইভেন্ট ইস্যু মোকাবিলা করতে)

সামগ্রিক দৃষ্টিকোণ থেকে, স্পর্শ ইভেন্টের প্রবাহটি শুরু হয় Activity, তারপরে নিচে প্রবাহিত হয় (পিতামাতার কাছ থেকে শিশু বিন্যাসে), এবং তারপরে দর্শনে। (নিম্নলিখিত ছবিতে এলটিআর প্রবাহ)

এখানে চিত্র বর্ণনা লিখুন

স্পর্শ ইভেন্টের লক্ষ্য দৃশ্য ছুঁয়েছে, দৃশ্য সব ব্যবস্থা করতে সক্ষম ঘটনা তারপর পূর্বে লেআউট / কার্যকলাপ বা না (ফিরে এটা পাস করার সিদ্ধান্ত নেন falseএর trueমধ্যে onTouchপদ্ধতি)। (উপরের ছবিতে আরটিএল প্রবাহ)

এখন আসুন স্পর্শ ইভেন্ট প্রবাহের আরও গভীর অন্তর্দৃষ্টি পেতে ভিউর উত্স কোডটি একবার দেখুন । এর বাস্তবায়নটি একবার দেখে dispatchTouchEvent, আমরা দেখতে পাব যে আপনি যদি ভিউটিতে সেট OnTouchListenerকরেন এবং তারপথে আবার ফিরে trueযান, দর্শনটির onTouchদৃষ্টিগোচর করা onTouchEventহবে না।

public boolean dispatchTouchEvent(MotionEvent event) {
    // removed lines for conciseness...
    boolean result = false;    
    // removed lines for conciseness...
    if (onFilterTouchEventForSecurity(event)) {
        // removed lines for conciseness...
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) { // <== right here!
            result = true;
        }
        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }
    // removed lines for conciseness...
    return result;
}

এখন, onTouchEventইভেন্টটির ক্রিয়াটি পদ্ধতিটি দেখুন MotionEvent.ACTION_UP। আমরা দেখতে পাই যে পারফর্ম-ক্লিকের ক্রিয়াটি সেখানে ঘটে। সুতরাং, ফিরে trueমধ্যে OnTouchListenerএর onTouchএবং এর ফলে কলিং না onTouchEvent, কলিং না ঘটায় OnClickListeners 'এর onClick

কল না করার সাথে আরও একটি সমস্যা রয়েছে onTouchEventযা চাপযুক্ত-রাষ্ট্রের সাথে সম্পর্কিত এবং আপনি প্রশ্নে উল্লেখ করেছেন। যেহেতু আমরা নীচের কোড ব্লকে দেখতে পাচ্ছি, যখন UnsetPressedStateকলগুলি চালিত হয় তখন একটি কল রয়েছে । কল না করার ফলস্বরূপ দর্শনটি চাপ দেওয়া অবস্থায় আটকে যায় এবং এর আঁকতে রাজ্যের পরিবর্তন হয় না। setPressed(false)setPressed(false)

public boolean onTouchEvent(MotionEvent event) {
    // removed lines for conciseness...
    if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
        switch (action) {
            case MotionEvent.ACTION_UP:
                // removed lines for conciseness...
                if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                    // removed lines for conciseness...
                    if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                        // removed lines for conciseness...
                        if (!focusTaken) {
                            // Use a Runnable and post this rather than calling
                            // performClick directly. This lets other visual state
                            // of the view update before click actions start.
                            if (mPerformClick == null) {
                                mPerformClick = new PerformClick();
                            }
                            if (!post(mPerformClick)) {
                                performClickInternal();
                            }
                        }
                    }
                    if (mUnsetPressedState == null) {
                        mUnsetPressedState = new UnsetPressedState();
                    }
                    if (prepressed) {
                        postDelayed(mUnsetPressedState,
                                ViewConfiguration.getPressedStateDuration());
                    } else if (!post(mUnsetPressedState)) {
                        // If the post failed, unpress right now
                        mUnsetPressedState.run();
                    }
                    // removed lines for conciseness...
                }
                // removed lines for conciseness...
                break;
            // removed lines for conciseness...
        }
        return true;
    }
    return false;
}

আনসেটপ্রেসড স্টেট :

private final class UnsetPressedState implements Runnable {
    @Override
    public void run() {
        setPressed(false);
    }
}


উপরের বর্ণনার বিষয়ে, setPressed(false)ইভেন্টের ক্রিয়াটি যেখানে রয়েছে সেই স্থিতিশীল রাষ্ট্রটি পরিবর্তন করার জন্য নিজেকে কল করে আপনি কোডটি পরিবর্তন করতে পারেন MotionEvent.ACTION_UP:

button.setOnTouchListener(new View.OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                v.invalidate();
                break;
            }
            case MotionEvent.ACTION_UP: {
                v.getBackground().clearColorFilter();
                // v.invalidate();
                v.setPressed(false);
                v.performClick();
                Log.d("Test", "Performing click");
                return true;
            }
        }
        return false;
    }
});

আমি আমার বন্ধুকে এটি খুঁজছি না। আমি উপরে বর্ণিত দুটি পরিস্থিতিতেই আচরণের পরিবর্তনটি বুঝতে চাই। যদি আমি এখানে আরও কিছু বলতে পারি তবে দয়া করে আমাকে জানান। আমি টাচ হ্যান্ডলারটি বা ক্লিক হ্যান্ডলারটি মুছতে চাই না। উপরের উত্তরে আমার মন্তব্য দেখুন।
হোয়াইটবিয়ার

@ হোয়াইটবিয়ার: আমি উত্তর আপডেট করেছি। দয়া করে এটি পরীক্ষা করে দেখুন, বন্ধু
অ্যামিনোগ্রাফি

এটি একটি ভাল বিস্তারিত উত্তর, এবং আমি এটি গ্রহণ করব। পরিবর্তন করতে কয়েকটি পয়েন্টার: Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.আমার ক্ষেত্রে অনক্লিক বলা হয়। মিউনসেটপ্রেসড স্টেটটি পরীক্ষা করে এটি মিথ্যাতে সেট করার আগে তা বাতিল হয়ে যায় এবং রান্নেবলও নিশ্চিত হয় না যে আমরা চাপে থাকলে তা চালানো যায়। আপনি কীভাবে এটি কেটে ফেলেন তা পুরোপুরি বুঝতে পারি না যে এটি মিথ্যা হিসাবে সেট করা উচিত
হোয়াইটবিয়ার

onClickনামক কারণ আপনার আহ্বান করা হয় করা হয় v.performClick();। দয়া করে MotionEvent.ACTION_UPআবার বিভাগে উপরের কোডটি চেক করুন , setPressed(false)যাইহোক বলা হয়, mUnsetPressedStateনাল হোক বা না হোক prepressed, সত্য বা না হোক or পার্থক্যটি কল করার পথে setPressed(false)যা সরাসরি post/ postDelayedবা সরাসরি মাধ্যমে হতে পারে ।
অ্যামিনোগ্রাফি

2

আপনি চারপাশে গোলযোগ করছেন touchএবং focusঘটনাগুলি। একই রঙ দিয়ে বোঝার আচরণ দিয়ে শুরু করা যাক। ডিফল্টরূপে, অ্যান্ড্রয়েডে Selectorব্যাকগ্রাউন্ড হিসাবে নির্ধারিত হয় Button। সুতরাং কেবল ব্যাকগ্রাউন্ডের রঙ পরিবর্তন করা, মেক স্ট্যাটিক (রঙ পরিবর্তন হবে না)। তবে এটি কোনও দেশীয় আচরণ নয়।

Selector এই মত চেহারা হতে পারে।

<?xml version="1.0" encoding="utf-8"?> 
  <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_focused="true"
        android:state_pressed="true"
        android:drawable="@drawable/bgalt" />

    <item
        android:state_focused="false"
        android:state_pressed="true"
        android:drawable="@drawable/bgalt" />

    <item android:drawable="@drawable/bgnorm" />
</selector>

আপনি উপরে দেখতে পারেন যে রাষ্ট্র focusedএবং রাষ্ট্র আছে pressed। সেট করে onTouchListenerআপনি স্পর্শ ইভেন্টগুলি পরিচালনা করবেন, যার কোনও সম্পর্ক নেই focus

Selectorবাটনের ক্লিক ইভেন্টের focusসাথে touchবোতামে ইভেন্টটি প্রতিস্থাপন করা উচিত । তবে আপনার কোডের প্রথম অংশে আপনি ইভেন্টগুলি touch(কলব্যাক থেকে সত্য ফিরে আসছেন) বাধা দিয়েছেন। রঙ পরিবর্তন আরও এগিয়ে যেতে পারে না এবং একই রঙের সাথে হিমশীতল। এবং সে কারণেই দ্বিতীয় রূপটি (কোনও বাধা ছাড়াই) ভাল কাজ করছে এবং এটিই আপনার বিভ্রান্তি।

হালনাগাদ

এর জন্য আচরণ এবং রঙ পরিবর্তন করার জন্য আপনাকে যা করার দরকার তা হ'ল Selector। প্রাক্তন জন্য। জন্য পরবর্তী পটভূমি ব্যবহার করে ButtonএবংonTouchListener আপনার বাস্তবায়ন থেকে একেবারে সরান ।

<?xml version="1.0" encoding="utf-8"?> 
  <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:drawable="@color/color_pressed" />

    <item android:drawable="@color/color_normal" />
</selector>

আপনি কিভাবে ভাল কাজ প্রথম উদাহরণ পরিবর্তন করতে হবে?
হোয়াইটবিয়ার

আমি আমার বাস্তবায়ন থেকে টাচ শ্রোতাদের সরাতে চাই না। যেহেতু আমি স্পর্শ হ্যান্ডলারটি ব্যবহার করে কোনও নির্দিষ্ট দৃশ্যে ক্লিকগুলি ধরতে চাই এবং তারপরে সেগুলি নিজেই পরিচালনা করব (পারফরম্যান্স ক্লিক করুন) এবং অন্যান্য হ্যান্ডলারের কাছে যাতে আর কোনও হ্যান্ডলিং করা হয় না তা জানানোর জন্য টাচ শ্রোতার কাছ থেকে সত্য ফিরে আসতে পারি। লগগুলি আমার উদাহরণে সূক্ষ্মভাবে মুদ্রিত হয়, তবুও বোতামটি হাইলাইট থাকে।
হোয়াইটবিয়ার

@ হোয়াইটবিয়ার আপনি নিজের প্রশ্নের মধ্যে এটি উল্লেখ করেন নি। যে কোনও উপায়ে, আপনি onTouchListenerযতগুলি চান আপনার ব্যবহার করতে পারেন। আপনার কেবল ইভেন্ট গ্রাস করার দরকার নেই return true
GensaGames

@ হোয়াইটবিয়ার বা নির্বাচক সরান এবং এর মাধ্যমে বোতামে কাঁচা রঙ সেট করুন backgroundColor
GensaGames

ছেলেরা, আমি এখনও মূল পোস্টে যা লিখেছি তা আপনি সম্বোধন করছেন না ..
হোয়াইটবিয়ার

0

আপনি যদি বোতামটিতে একটি পটভূমি বরাদ্দ করেন তবে এটি ক্লিকের রঙ পরিবর্তন করবে না।

 <color name="myColor">#000000</color>

এবং এটিকে আপনার বোতামে ব্যাকগ্রাউন্ট হিসাবে সেট করুন

android:background="@color/myColor"

0

আপনি বাটন দেখার পরিবর্তে কেবল উপাদান চিপস ব্যবহার করতে পারেন। রেফারেন্স: https://matory.io/develop/android/components/chip সেখানে তারা এই সমস্ত আবদ্ধ ইভেন্টগুলি পরিচালনা করে এবং আপনি থিমগুলি প্রয়োগ করে কাস্টমাইজ করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.