যখন আপনি একটি লেআউট আঁকা হয়েছে কিভাবে বলতে পারেন?


201

আমার একটি কাস্টম ভিউ রয়েছে যা স্ক্রিনে একটি স্ক্রোলযোগ্য বিটম্যাপ আঁকে। এটি আরম্ভ করার জন্য, আমাকে প্যারেন্ট লেআউট অবজেক্টের পিক্সেল আকারে পাস করতে হবে। তবে অনক্রিট এবং অন-পুনরায় কর্মের সময়, লেআউটটি এখনও অঙ্কিত হয়নি, এবং তাই বিন্যাস.সেটমিউজডহাইট () 0 প্রদান করে।

কার্যকারণ হিসাবে, আমি এক সেকেন্ড অপেক্ষা করতে এবং তারপরে পরিমাপের জন্য একটি হ্যান্ডলার যুক্ত করেছি। এটি কাজ করে, তবে এটির ,ালু এবং লেআউটটি আঁকানোর আগে শেষ হওয়ার আগে আমি সময়টি কতটা ছাঁটাই করতে পারি তা আমার কোনও ধারণা নেই।

আমি যা জানতে চাই তা হ'ল, যখন কোনও বিন্যাস আঁকা যায় তখন আমি কীভাবে সনাক্ত করতে পারি? কোন ইভেন্ট বা কলব্যাক আছে?

উত্তর:


391

আপনি বিন্যাসে একটি ট্রি পর্যবেক্ষক যুক্ত করতে পারেন। এটি সঠিক প্রস্থ এবং উচ্চতা ফিরে আসা উচিত। onCreate()সন্তানের মতামতের বিন্যাস সম্পন্ন হওয়ার আগে তাকে বলা হয়। প্রস্থ এবং উচ্চতা এখনও গণনা করা হয় না। উচ্চতা এবং প্রস্থ পেতে, এটিকে এই onCreate()পদ্ধতিতে রাখুন:

    final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);
    ViewTreeObserver vto = layout.getViewTreeObserver(); 
    vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() { 
        @Override 
        public void onGlobalLayout() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    layout.getViewTreeObserver()
                            .removeOnGlobalLayoutListener(this);
                } else {
                    layout.getViewTreeObserver()
                            .removeGlobalOnLayoutListener(this);
                }
            int width  = layout.getMeasuredWidth();
            int height = layout.getMeasuredHeight(); 

        } 
    });

28
আপনাকে অনেক ধন্যবাদ! তবে আমি ভাবছি কেন এটি করার সহজ সরল পদ্ধতি নেই কারণ এটি একটি সাধারণ সমস্যা।
ফেলিক্সড

1
অ্যামেজিং। আমি অন-লেআউটচ্যাঞ্জলিস্টনার চেষ্টা করেছি এবং এটি কার্যকর হয়নি। তবে অ্যানগ্লোবাললআউটলিস্টনার কাজ করেছেন। তোমাকে অনেক ধন্যবাদ!
YoYoMyo

8
সরানগ্লোবালআনলয়আউটলিস্টনার এপিআই লেভেল 16 এ অবমুক্ত করা হয়েছে instead
Tounaobun

3
আমি দেখতে পাচ্ছি এমন একটি "গোছা" হ'ল যদি আপনার দৃষ্টিভঙ্গিটি দৃশ্যমান না হয় তবে অন্লোবাললয়আউট বলা হয় তবে পরে যখন দেখা যায় তখন ভিটভিউ বলা হয়, কিন্তু অন গ্লোবাললয়আউট না ... উঘ।
স্টিফেন ম্যাককর্মিক

1
এর আরও একটি দ্রুত সমাধান হ'ল view.post(Runnable)এটি পরিষ্কার করা এবং এটি একই কাজ করে।
ডিভিডিসিরি

74

একটি সহজ উপায় হ'ল কেবল post()আপনার বিন্যাসে কল করা। আপনার ভিউ ইতিমধ্যে তৈরি হওয়ার পরে এটি পরবর্তী কোডটি আপনার কোডটি চালাবে।

YOUR_LAYOUT.post( new Runnable() {
    @Override
    public void run() {
        int width  = YOUR_LAYOUT.getMeasuredWidth();
        int height = YOUR_LAYOUT.getMeasuredHeight(); 
    }
});

4
আমি জানি না ভিউ ইতিমধ্যে তৈরি হওয়ার পরে পোস্টটি আসলে আপনার কোড চালাবে কিনা। কোনও গ্যারান্টি নেই, যেহেতু পোস্টটি আপনি রানউইউতে তৈরি করা রান্নেবলকে যুক্ত করবে, ইউআই থ্রেডে মৃত্যুদন্ড কার্যকর করা পূর্ববর্তী সারির পরে কার্যকর করা হবে।
হেন্দ্রডাব্লুডি

4
বিপরীতে, পোস্ট () পরবর্তী ইউআই পদক্ষেপ আপডেটের পরে কার্যকর করে, যা ভিউ তৈরি হওয়ার পরে ঘটে। অতএব, আপনি গ্যারান্টিযুক্ত যে ভিউ তৈরি হওয়ার পরে এটি কার্যকর হবে।
এলিপটিকা

আমি এই কোডটি বেশ কয়েকবার পরীক্ষা করেছি, এটি কেবলমাত্র ইউআই-থ্রেডে সেরা কাজ করে। একটি পটভূমি থ্রেডে এটি কখনও কখনও কাজ করে না।
কুলমাইন্ড

3
@HendraWijayaDjiono, হয়তো এই পোস্টে উত্তর দিতে হবে: stackoverflow.com/questions/21937224/...
CoolMind

1
আমি একটি ইস্যুতে ছড়িয়ে পড়েছি যেখানে প্রথম উত্তরটি ব্যবহার করা প্রতিটি সময় কাজ করে না, স্ক্রোল করার জন্য আমার যে ভিউ (স্ক্রোল ভিউ) প্রয়োজন ছিল তার পোস্ট ব্যবহার করে, ভিউটি প্রস্তুত হওয়ার সাথে সাথেই আমাকে পছন্দসই পজিশনে সঠিকভাবে স্ক্রোল করার অনুমতি দিয়েছে view স্ক্রোলটো পদ্ধতি কল।
ডানুফার

21

অবহেলিত কোড এবং সতর্কতাগুলি এড়াতে আপনি ব্যবহার করতে পারেন:

view.getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {
            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    view.getViewTreeObserver()
                            .removeOnGlobalLayoutListener(this);
                } else {
                    view.getViewTreeObserver()
                            .removeGlobalOnLayoutListener(this);
                }
                yourFunctionHere();
            }
        });

1
এই কোডটি ব্যবহার করতে, 'ভিউ'কে অবশ্যই' চূড়ান্ত 'হিসাবে ঘোষণা করতে হবে।
বেকাপ

2
এই অবস্থা বদলে Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN ব্যবহার
HendraWD

4

কোটলিন এক্সটেনশন ফাংশনগুলির সাথে আরও ভাল

inline fun View.waitForLayout(crossinline yourAction: () -> Unit) {
    val vto = viewTreeObserver
    vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            when {
                vto.isAlive -> {
                    vto.removeOnGlobalLayoutListener(this)
                    yourAction()
                }
                else -> viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        }
    })
}

খুব সুন্দর এবং মার্জিত সমাধান যা পুনরায় ব্যবহার করা যেতে পারে।
আয়নুত নেগ্রু


3

সাধারণ পদ্ধতির বিকল্প হ'ল ভিউয়ের অঙ্কনটি .োকানো।

OnPreDrawListenerএকটি দৃশ্য প্রদর্শন করার সময় বহুবার ডাকা হয়, সুতরাং কোনও নির্দিষ্ট পুনরাবৃত্তি নেই যেখানে আপনার দর্শনটির বৈধ পরিমাপ করা প্রস্থ বা উচ্চতা রয়েছে। এটির জন্য আপনি ক্রমাগত যাচাই করে ( view.getMeasuredWidth() <= 0) বা measuredWidthশূন্যের চেয়ে বেশি সময় যাচাই করেন তার সীমা নির্ধারণ করে that

এমনও সুযোগ রয়েছে যে দৃশ্যটি কখনই আঁকবে না, যা আপনার কোড সহ অন্যান্য সমস্যাগুলি ইঙ্গিত করতে পারে।

final View view = [ACQUIRE REFERENCE]; // Must be declared final for inner class
ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        if (view.getMeasuredWidth() > 0) {     
            view.getViewTreeObserver().removeOnPreDrawListener(this);
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
            //Do something with width and height here!
        }
        return true; // Continue with the draw pass, as not to stop it
    }
});

প্রশ্নটি হল How can you tell when a layout has been drawn?এবং আপনি এমন একটি পদ্ধতি সরবরাহ করছেন যেখানে আপনি কল করেন OnPreDrawListenerএবং don't stop interrogating that view until it has provided you with a reasonable answerতাই আপনার সমাধানের আপত্তিটি সুস্পষ্ট হওয়া উচিত।
পরিত্যক্ত কার্ট

আপনার যা জানা দরকার তা কখন আঁকানো হয় তা নয় তবে কখন এটি পরিমাপ করা হয়েছিল। আমার কোড সেই প্রশ্নের উত্তর দেয় যা সত্যই জিজ্ঞাসা করা উচিত।
জোহরেল

এই সমাধানে কিছু সমস্যা আছে? এটি সমস্যার মুখোমুখি সমাধান করতে ব্যর্থ হয়?
জয়ওয়ার্ল

1
ভিউটি নির্ধারিত না হওয়া পর্যন্ত পরিমাপ করা হয় না, সুতরাং এই বিকল্পটি অত্যধিক এবং অপ্রয়োজনীয় চেক সম্পাদন করে। আপনি প্রশ্নটি সম্বোধন না করার বিষয়টি স্বীকার করেছেন, তবে আপনার যা মনে হচ্ছে তা জিজ্ঞাসা করা উচিত। মূল মন্তব্যটি এই দুটি পয়েন্টই করেছে, তবে কোডটি নিজেই কিছু সমস্যা রয়েছে যা সম্পাদনা হিসাবে জমা দেওয়া হয়েছে।
পরিত্যক্ত কার্ট

এটি একটি দুর্দান্ত সম্পাদনা। ধন্যবাদ. আমি অনুমান করি যা আমি জিজ্ঞাসা করছি এটি কি আপনি মনে করেন যে এই উত্তরটি মুছে ফেলা উচিত বা না? আমি ওপি-র সমস্যার মুখোমুখি হয়েছি। এটি সমস্যার সমাধান করেছে। আমি এটি ভাল বিশ্বাসের সাথে অফার করেছি। এটা কি ভুল ছিল? এটি কি এমন কিছু যা স্ট্যাকওভারফ্লোতে করা উচিত নয়?
জোহরলে

2

আপনার লেআউট বা ভিউতে পোস্ট পদ্ধতিতে কল করে কেবল এটি পরীক্ষা করুন

 view.post( new Runnable() {
     @Override
     public void run() {
        // your layout is now drawn completely , use it here.
      }
});

এটি সত্য নয় এবং সম্ভাব্য সমস্যাগুলি গোপন করতে পারে। postএর পরে দৌড়ানোর জন্য রান করার যোগ্য কিউ তৈরি করবে, এটি ভিউ পরিমাপ করা হয় এমনকী, এমনকি কম টানাও নিশ্চিত করে না।
আয়নুত নেগ্রু

@IonutNegru হয়তো এই পড়া stackoverflow.com/a/21938380
ব্রুনো Bieri

ব্রুনোবিয়েরি, আপনি এ্যাসিঙ্ক ফাংশনগুলির সাথে এই আচরণটি পরীক্ষা করতে পারেন যা ভিউয়ের পরিমাপকে পরিবর্তন করে এবং আপনার সারিবদ্ধ কাজটি প্রতিটি পরিমাপের পরে চালানো হচ্ছে কিনা এবং প্রত্যাশিত মানগুলি অর্জন করতে পারেন see
আয়নুত নেগ্রু

1

যখন onMeasureডাকা হয় দৃশ্যটি তার পরিমাপ করা প্রস্থ / উচ্চতা পায়। এই পরে, আপনি কল করতে পারেন layout.getMeasuredHeight()


4
OnMeasure Fires জানতে আপনার নিজের কাস্টম ভিউ তৈরি করতে হবে না?
গিগস অন হিগস

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