onMeasure কাস্টম ভিউ ব্যাখ্যা


316

আমি কাস্টম উপাদানটি করার চেষ্টা করেছি। আমি Viewক্লাস বাড়িয়েছি এবং onDrawওভাররাইড পদ্ধতিতে কিছু অঙ্কন করি । আমার কেন ওভাররাইড করা দরকার onMeasure? যদি আমি না করি তবে সবকিছু ঠিক আছে বলে দেখা গেছে। কেউ এটি ব্যাখ্যা করতে পারেন? আমার onMeasureপদ্ধতিটি কীভাবে লিখব ? আমি দু'টি টিউটোরিয়াল দেখেছি, তবে প্রত্যেকটি একে অপরের চেয়ে কিছুটা আলাদা। কখনও কখনও তারা কল super.onMeasureকরে, কখনও কখনও তারা ব্যবহার করে setMeasuredDimensionএবং কল করে না call কোথায় পার্থক্য?

সর্বোপরি আমি বেশ কয়েকটি একই উপাদান ব্যবহার করতে চাই। আমি সেই XMLফাইলগুলি আমার ফাইলে যুক্ত করেছি, তবে সেগুলি কত বড় হওয়া উচিত তা আমি জানি না। আমি কাস্টম কম্পোনেন্ট শ্রেণিতে পরে এর অবস্থান এবং আকারটি সেট করতে চাই (কেন আমি এটি আঁকতে, পাশাপাশি কাজ করতে onMeasureচাইলে আকার কেন সেট করতে onDrawহবে)। আমি কখন এটা করতে হবে?

উত্তর:


735

onMeasure()আপনার কাস্টম ভিউটি পিতামাতার দ্বারা সরবরাহিত বিন্যাসের সীমাবদ্ধতার উপর নির্ভরশীল হওয়া কতটা বড় চান তা অ্যান্ড্রয়েডকে বলার সুযোগ is এই লেআউটের সীমাবদ্ধতাগুলি কী তা শেখার জন্য আপনার কাস্টম ভিউয়ের সুযোগ (আপনি যদি কোনও match_parentপরিস্থিতির চেয়ে পরিস্থিতি থেকে আলাদা আচরণ করতে চান wrap_content)। এই সীমাবদ্ধতাগুলি MeasureSpecপদ্ধতিতে পাস হওয়া মানগুলিতে প্যাক করা হয় । এখানে মোডের মানগুলির মোটামুটি পারস্পরিক সম্পর্ক রয়েছে:

  • অবিকল অর্থ layout_widthবা layout_heightমানটি একটি নির্দিষ্ট মানকে সেট করা হয়েছিল। আপনার সম্ভবত এই দৃশ্যটি আপনার আকার করা উচিত। match_parentপ্যারেন্ট ভিউয়ের ঠিক আকার নির্ধারণ করতে (এটি ফ্রেমওয়ার্কের উপর নির্ভরশীল লেআউট) ব্যবহার করার সময় এটি ট্রিগারও পেতে পারে।
  • AT_MOST সাধারণত অর্থ layout_widthবা layout_heightমান সেট করা হয়েছিল match_parentবা wrap_contentযেখানে সর্বোচ্চ আকার প্রয়োজন (এটি ফ্রেমওয়ার্কের উপর নির্ভরশীল লেআউট), এবং প্যারেন্ট মাত্রার আকারটি মান is আপনার এই আকারের চেয়ে বড় হওয়া উচিত নয়।
  • UNSPECIFIED এর অর্থ সাধারণত layout_widthবা layout_heightমানটি wrap_contentকোনও সীমাবদ্ধতা ছাড়াই সেট করা হয়েছিল । আপনার পছন্দ মতো আকার হতে পারে। কিছু লেআউট এছাড়াও এই কলব্যাকটি ব্যবহার করে আপনার পছন্দসই আকারটি বের করার আগে আপনাকে কী দ্বিতীয় ধাপের অনুরোধে পুনরায় পাস করতে হবে তা নির্ধারণের আগে desired

চুক্তি যে বিদ্যমান onMeasure()যে setMeasuredDimension() হবে আকার সঙ্গে শেষে বলা যেতে আপনি দৃশ্য হতে চাই। এই পদ্ধতিটি সমস্ত ফ্রেমওয়ার্ক বাস্তবায়নের সাথে ডাকা হয়, এতে পাওয়া ডিফল্ট বাস্তবায়নও অন্তর্ভুক্ত থাকে View, এজন্য এটি superযদি আপনার ব্যবহারের ক্ষেত্রে ফিট করে তবে পরিবর্তে কল করা নিরাপদ ।

মঞ্জুর, কারণ কাঠামোটি একটি ডিফল্ট বাস্তবায়ন প্রয়োগ করে, আপনার পক্ষে এই পদ্ধতিটি ওভাররাইড করা প্রয়োজন হতে পারে না, তবে আপনি যদি না করেন তবে দৃশ্য স্থানটি আপনার সামগ্রীর চেয়ে কম ছোট হবে এবং আপনি যদি নিজের জায়গাটি রেখে দেন তবে আপনি ক্লিপিং দেখতে পাবেন your wrap_contentউভয় দিকের সাথে কাস্টম ভিউ , আপনার দৃষ্টিভঙ্গিটি সম্ভবত প্রদর্শিত হবে না কারণ কাঠামোটি এটি কত বড় তা জানে না!

সাধারণত, আপনি যদি ওভাররাইডিং করে থাকেন Viewএবং অন্য বিদ্যমান উইজেট না হন তবে এটি বাস্তবায়ন দেওয়ার পক্ষে সম্ভবত এটি ভাল ধারণা, যদিও এটি এর মতো কিছু সাধারণ হিসাবে সহজ:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
        //Must be this size
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        width = Math.min(desiredWidth, widthSize);
    } else {
        //Be whatever you want
        width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
        //Must be this size
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        height = Math.min(desiredHeight, heightSize);
    } else {
        //Be whatever you want
        height = desiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);
}

আশা করি এইটি কাজ করবে.


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

47
মনে রাখবেন যে আপনি যদি কোনও ভিউগ্রুপ সাবক্লাসের ওজনমাধ্যমে ওভাররাইড করেন তবে এই কোডটি করবে না। আপনার সাবভিউগুলি প্রদর্শিত হবে না এবং সকলের আকার 0x0 হবে। আপনার যদি কাস্টম ভিউগ্রুপের ওভাররাইডের প্রয়োজন হয়, প্রস্থমোড, চওড়া আকার, উচ্চতামোড এবং হাইটসাইজ পরিবর্তন করুন, মেজারস্পেক.মেকমেজারস্পেক ব্যবহার করে তাদের পরিমাপের স্পেসগুলিতে আবার সংকলন করুন এবং ফলস্বরূপ পূর্বে পূর্ণরূপটি super.onMeasure এ পাস করুন।
আলেক্সি

1
চমত্কার উত্তর। নোট করুন, গুগলের ডকুমেন্টেশন অনুসারে প্যাডিং পরিচালনা করা ভিউয়ের দায়িত্ব।
jonstaff

4
জটিল সি ** পি এর বেশি যা অ্যান্ড্রয়েডকে কাজ করতে একটি বেদনাদায়ক লেআউট সিস্টেম তৈরি করে। তাদের সবেমাত্র পিতামাতা () পেতে পেতেন *** () ...
অলিভার ডিকসন

2
Viewক্লাসে সাহায্যকারী পদ্ধতি রয়েছে , বলা হয় resolveSizeAndStateএবং resolveSizeএটি 'যদি' ক্লজগুলি করে তবে তা করা উচিত - আমি সেগুলি দরকারী বলে মনে করি বিশেষত যদি আপনাকে প্রায়শই IF গুলি লিখতে হয়।
stan0

5

প্রকৃতপক্ষে, আপনার উত্তর সম্পূর্ণ নয় কারণ মানগুলি মোড়ানো পাত্রেও নির্ভর করে। আপেক্ষিক বা লিনিয়ার লেআউটের ক্ষেত্রে মানগুলি এই জাতীয় আচরণ করে:

  • ঠিক match_parent ঠিক + + পিতা বা মাতা আকার
  • AT_MOST মোড়কের_ A কনটেন্টের ফলাফল AT_MOST পরিমাপের স্পেসে p
  • নির্ধারিত কখনও ট্রিগার হয়নি

একটি অনুভূমিক স্ক্রোল ভিউয়ের ক্ষেত্রে, আপনার কোডটি কাজ করবে।


57
আপনি যদি মনে করেন যে এখানে কিছু উত্তর অসম্পূর্ণ, দয়া করে একটি আংশিক উত্তর দেওয়ার পরিবর্তে এটিতে যুক্ত করুন।
মিশাল

1
লেআউটগুলি কীভাবে কাজ করে এটির সাথে লিঙ্ক করার জন্য ভাল ওন্যা, তবে আমার ক্ষেত্রে onMeasure আমার কাস্টম ভিউয়ের জন্য তিনবার বলা হয়। প্রশ্নের দর্শনটিতে একটি মোড়ানো_মূর্তিযুক্ত উচ্চতা এবং ওজনযুক্ত প্রস্থ ছিল (প্রস্থ = 0, ওজন = 1)। প্রথম কলটিতে UNSPECIFIED / UNSPECIFIED, দ্বিতীয়টিতে AT_MOST / যথাযথ এবং তৃতীয়টিতে যথাযথ / অবিকল ছিল।
উইলিয়াম টি। ম্যালার্ড

0

আপনার যদি onMeasure কিছু পরিবর্তন করার প্রয়োজন না হয় - এটির ওভাররাইড করার জন্য আপনার একেবারেই দরকার নেই।

ডিভনওয়ায়ার্ড কোড (এখানে নির্বাচিত এবং সর্বাধিক ভোট দেওয়া উত্তর) এসডিকে বাস্তবায়ন ইতিমধ্যে আপনার জন্য যা করেছে তার প্রায় অনুরূপ (এবং আমি পরীক্ষা করে দেখেছি - এটি ২০০৯ সাল থেকে এটি করেছিল)।

আপনি এখানে onMeasure পদ্ধতি পরীক্ষা করতে পারেন :

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

public static int getDefaultSize(int size, int measureSpec) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}

ওভাররাইডিং এসডিকে কোডটিকে একই কোডের সাথে প্রতিস্থাপন করা কোনও অর্থবোধ করে না।

এই অফিশিয়াল ডকের অংশটি দাবি করে যে "ডিফল্ট onMeasure () সর্বদা 100x100 এর আকার সেট করে" - এটি ভুল is

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