রানটাইমটিতে একটি অ্যান্ড্রয়েড ভিউয়ের আকার নির্ধারণ করা


123

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

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

ImageView myView = (ImageView) getWindow().findViewById(R.id.MyViewID);

এই কাজ করে জরিমানা, কিন্তু কলিং getWidth(), getHeight(), getMeasuredWidth(), getLayoutParams().widthইত্যাদি তারা সব রিটার্ন 0. আমি কলিং নিজে চেষ্টা করেছি measure()দৃশ্য একটি কল দ্বারা অনুসরণgetMeasuredWidth() , কিন্তু যে কোনো প্রভাব নেই।

আমি এই পদ্ধতিগুলিতে কল করার চেষ্টা করেছি এবং আমার ক্রিয়াকলাপ onCreate()এবং এর মধ্যে ডিবাগারের মধ্যে অবজেক্টটি পর্যালোচনা করেছি onPostCreate()। রানটাইমে আমি এই দর্শনটির সঠিক মাত্রাগুলি কীভাবে সনাক্ত করতে পারি?


1
ওহ, আমি জানানো হচ্ছে যে দৃশ্য নিজেই স্পষ্টভাবে নেই না 0 প্রস্থ / উচ্চতা আছে। এটি ঠিকঠাক পর্দায় প্রদর্শিত হবে।
নিক রেইমান

আপনি কি এক্সএমএল লেআউট থেকে <ইমেজভিউ ... /> ট্যাগ পোস্ট করতে পারেন?
fhucho

আমি এই সমস্যার অনেকগুলি সমাধানের সাথে লড়াই করেছি যতক্ষণ না আমি বুঝতে পেরেছিলাম যে আমার ক্ষেত্রে দৃশ্যের মাত্রাগুলি শারীরিক স্ক্রিনের সাথে মিলেছে (আমার অ্যাপ্লিকেশনটি "মগ্ন" এবং ভিউ এবং এর সমস্ত পিতামাতার প্রস্থ এবং উচ্চতা সেট করা নেই match_parent)। এই ক্ষেত্রে, ভিউটি আঁকার আগেই নিরাপদে বলা যেতে পারে এমন একটি সহজ সমাধান (উদাহরণস্বরূপ, আপনার ক্রিয়াকলাপের অনক্রিট () পদ্ধতি থেকে) কেবল প্রদর্শন.সেটসাইজ () ব্যবহার করা যায়; বিশদ জানতে stackoverflow.com/a/30929599/5025060 দেখুন। আমি জানি যে এটি নিক রীমন যা চেয়েছিল তা নয়, যারা এই সহজ পদ্ধতিটি ব্যবহার করতে সক্ষম হতে পারে তাদের কেবল একটি নোট রেখে যান।

উত্তর:


180

প্রথম লেআউটের জন্য অপেক্ষা করতে ভিউতে ভিউটিউজারবার ব্যবহার করুন। প্রথম লেআউটের পরে কেবলমাত্র উইডথ () / getHeight () / getMeasuredWidth () / getMeasuredHeight () কাজ পাবেন।

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
  viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
      viewWidth = view.getWidth();
      viewHeight = view.getHeight();
    }
  });
}

21
এই উত্তরটি সম্পর্কে সতর্ক থাকুন কারণ অন্তর্নিহিত ভিউটি কোনও ভিডিও / পৃষ্ঠ হিসাবে থাকলে এটি অবিচ্ছিন্নভাবে বলা হবে
কেভিন পার্কার

7
আপনি কি এই @ কেভিনের বিস্তারিত বর্ণনা করতে পারেন? দুটি জিনিস, প্রথমত, যেহেতু এটি শ্রোতা, তাই আমি একটি একক কলব্যাক আশা করব এবং তারপরে, প্রথম কলব্যাক পাওয়ার সাথে সাথে আমরা শ্রোতাকে সরিয়ে ফেলব। আমি কি কিছু রেখে গেলাম?
বিক্রম বডিচেরলা

4
যে কোনও ভিউ ট্রিউজারবারের পদ্ধতিগুলি কল করার আগে এটির প্রস্তাবিত আইলাইভ () পরীক্ষা করা উচিত: যদি (দেখুন.getViewTreeObserver ()। IsAlive ())। View.getViewTreeObserver () remove }
পিটার ট্রান

4
কোন বিকল্প removeGlobalOnLayoutListener(this);? কারণ এটি হ্রাস করা হয়েছে।
সিবস জুয়াং

7
@ ফার্টিক্যালপিল্টার, এর পরিবর্তে অপসারণঅনগ্লোবাল লেআউটলিস্টনার () ব্যবহার করুন। এটি ডক্সে উল্লেখ করা হয়েছে।
বিক্রম বডিচেরলা

63

দৃশ্যের উপর নির্ভর করে আসলে একাধিক সমাধান রয়েছে:

  1. নিরাপদ পদ্ধতিটি, বিন্যাস পর্ব শেষ হওয়ার পরে দৃশ্যটি আঁকার ঠিক আগে কাজ করবে:
public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) {
    final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            view.getViewTreeObserver().removeOnPreDrawListener(this);
            runnable.run();
            return true;
        }
    };
    view.getViewTreeObserver().addOnPreDrawListener(preDrawListener); 
}

নমুনা ব্যবহার:

    ViewUtil.runJustBeforeBeingDrawn(yourView, new Runnable() {
        @Override
        public void run() {
            //Here you can safely get the view size (use "getWidth" and "getHeight"), and do whatever you wish with it
        }
    });
  1. কিছু ক্ষেত্রে, ভিউটির আকার ম্যানুয়ালি মাপার জন্য এটি যথেষ্ট:
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width=view.getMeasuredWidth(); 
int height=view.getMeasuredHeight();

আপনি যদি ধারকটির আকার জানেন তবে:

    val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST)
    val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxHeight, View.MeasureSpec.AT_MOST)
    view.measure(widthMeasureSpec, heightMeasureSpec)
    val width=view.measuredWidth
    val height=view.measuredHeight
  1. যদি আপনার কাস্টম ভিউ থাকে যা আপনি প্রসারিত করেছেন তবে আপনি "onMeasure" পদ্ধতিতে এর আকারটি পেতে পারেন, তবে আমি মনে করি এটি কেবল কিছু ক্ষেত্রে ভাল কাজ করে:
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
    final int newHeight= MeasureSpec.getSize(heightMeasureSpec);
    final int newWidth= MeasureSpec.getSize(widthMeasureSpec);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
  1. আপনি যদি কোটলিনে লিখেন তবে আপনি পরবর্তী ফাংশনটি ব্যবহার করতে পারেন, যা পর্দার আড়ালে ঠিক runJustBeforeBeingDrawnযেভাবে লিখেছি ঠিক তেমন কাজ করে :

    view.doOnPreDraw { actionToBeTriggered() }

    মনে রাখবেন আপনি gradle (মাধ্যমে পাওয়া এই যোগ করতে হবে এখানে ):

    implementation 'androidx.core:core-ktx:#.#'

1
মনে হয় যে সমাধান # 1 সর্বদা সাথে কাজ করবে না OnPreDrawListener। আপনি যখন ক্রিয়াকলাপের কোডটি চালাতে চান এবং ততক্ষনে onCreate()আপনি ব্যাকগ্রাউন্ড অ্যাপ্লিকেশনটি পরীক্ষা করেছেন। বিশেষত ধীর ডিভাইসে পুনরাবৃত্তি করা সহজ। যদি আপনি এর সাথে প্রতিস্থাপন OnPreDrawListenerকরেন OnGlobalLayoutListener- আপনি একই সমস্যা দেখতে পাবেন না।
প্রশ্নকারী

@ জিজ্ঞাসাবাদক আমি বুঝতে পারি না তবে শেষ পর্যন্ত এটি আপনাকে সহায়তা করেছে বলে আমি খুশি।
অ্যান্ড্রয়েড বিকাশকারী

যদিও আমি সাধারণত ব্যবহার করি ViewTreeObserverবা post, আমার ক্ষেত্রে নম্বর 2 সাহায্য করেছে ( view.measure)।
কুলমাইন্ড

3
@ কুলমাইন্ড আপনি কোটলিন ব্যবহারের ক্ষেত্রেও একটি নতুন পদ্ধতি ব্যবহার করতে পারেন। এটি অন্তর্ভুক্ত করার জন্য আপডেট উত্তর।
অ্যান্ড্রয়েড বিকাশকারী

কোটলিন এর জন্য অতিরিক্ত ফাংশন রাখে কেন? গুগল পাগল, এই ভাষাটি অকেজো (কেবল জাভা দিয়েই থাকতে হবে), এটি সুইফ্টের চেয়ে অনেক বেশি পুরানো তবে কেবল সুইফট যথেষ্ট জনপ্রিয়তা পেয়েছে tiobe.com/tiobe-index (সুইফট 12 অবস্থান এবং কোটলিন 38)
ইউজার 924

18

getWidth()দৃশ্যটি স্ক্রিনে ছড়িয়ে দেওয়ার আগে আপনি কি ফোন করছেন ?

নতুন অ্যান্ড্রয়েড বিকাশকারীদের দ্বারা করা একটি সাধারণ ভুল হ'ল এর নির্মাতার অভ্যন্তরে কোনও দৃশ্যের প্রস্থ এবং উচ্চতা ব্যবহার করা। যখন কোনও দৃশ্যের নির্মাণকারীকে ডাকা হয়, অ্যান্ড্রয়েড এখনও জানবে না যে ভিউটি কত বড় হবে, তাই আকারগুলি শূন্যতে সেট করা আছে। আসল আকারগুলি লেআউট পর্যায়ে গণনা করা হয়, যা নির্মাণের পরে ঘটে তবে কিছু আঁকানোর আগে ঘটে। onSizeChanged()মানগুলি জানার পরে আপনি বিজ্ঞপ্তি দেওয়ার পদ্ধতিটি ব্যবহার করতে পারেন , বা আপনি পদ্ধতিগুলি getWidth()এবং getHeight()পদ্ধতিগুলি পরে ব্যবহার করতে পারেন onDraw()method


2
সুতরাং এর অর্থ onSizeChange()কি আসল আকারটি জানতে ইভেন্টটি ধরার জন্য আমার কেবল চিত্র ভিউর ওভাররাইড করা দরকার ? এটি কিছুটা ওভারকিলের মতো মনে হচ্ছে ... যদিও এই মুহুর্তে আমি কেবল কোডটি কাজ করতে মরিয়া, তাই এটির জন্য একটি শট।
নিক রেইমান

আপনার অনক্রিট () আপনার ক্রিয়াকলাপটি শেষ না হওয়া পর্যন্ত আমি অপেক্ষা করার মতো আরও ভাবছিলাম।
বি

1
উল্লিখিত হিসাবে, আমি এই কোডটি দেওয়ার চেষ্টা করেছি onPostCreate()যাতে দর্শনটি সম্পূর্ণরূপে তৈরি এবং শুরু হওয়ার পরে চালিত হয়।
নিক রেইমান

1
উদ্ধৃত পাঠ্য কোথা থেকে এসেছে?
সূচনা

1
কাস্টম ভিউয়ের জন্য এই উক্তিটি, যখন আমরা সাধারণভাবে দেখার আকার সম্পর্কে জিজ্ঞাসা করি তখন এ জাতীয় উত্তরের জন্য পোস্ট করবেন না
user924

17

@ এমবায়ের্ডের পরামর্শের ভিত্তিতে, আমি ক্লাসটি সাবক্ল্যাসিং করে ImageViewওভাররাইড করে একটি কার্যক্ষম সমাধান পেয়েছিonLayout() । এরপরে আমি একটি পর্যবেক্ষক ইন্টারফেস তৈরি করেছি যা আমার ক্রিয়াকলাপ বাস্তবায়িত হয়েছিল এবং ক্লাসের কাছে নিজেই একটি রেফারেন্স দিয়েছিল, যা এটি যখন সাইজিংয়ের কাজটি শেষ করে আসলে কার্যকলাপটি বলতে দেয় tell

আমি ১০০% নিশ্চিত নই যে এটিই সেরা সমাধান (অতএব আমার এই উত্তরটি এখনও সঠিক হিসাবে চিহ্নিত করা হচ্ছে না), তবে এটি কার্যকর হয় এবং ডকুমেন্টেশন অনুসারে প্রথম বার যখন কোনও দৃশ্যের আসল আকার খুঁজে পাওয়া যায়।


জানা ভাল. যদি আমি এমন কোনও কিছু খুঁজে পাই যা আপনাকে এখানে উপস্থাপনের জন্য সাবক্লাস করার জন্য আপনাকে অনুমতি দেয় post পোস্টপ্রেসেট () কাজ করে নি আমি কিছুটা অবাক হয়েছি।
বি বি

ঠিক আছে, আমি এটি চেষ্টা করেছি এবং এটি কাজ করে বলে মনে হচ্ছে। শুরুতে একবারেই নয় এই পদ্ধতিটি ঘন ঘন কল হওয়ায় কেবল সেরা সমাধান নয়। :(
টোবিয়াস রিচ

10

যদি ভিআইপি <11 (এপিআই 11-এ ভিউ অন্তর্ভুক্ত থাকে তবে অন লেআউটচ্যাঞ্জডলাইজনার বৈশিষ্ট্য) যদি একটি ভিউ ওভাররাইডিংয়ের মাধ্যমে লেআউটটি পাওয়ার জন্য এখানে কোড থাকে:

public class CustomListView extends ListView
{
    private OnLayoutChangedListener layoutChangedListener;

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

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        if (layoutChangedListener != null)
        {
            layoutChangedListener.onLayout(changed, l, t, r, b);
        }
        super.onLayout(changed, l, t, r, b);
    }

    public void setLayoutChangedListener(
        OnLayoutChangedListener layoutChangedListener)
    {
        this.layoutChangedListener = layoutChangedListener;
    }
}
public interface OnLayoutChangedListener
{
    void onLayout(boolean changed, int l, int t, int r, int b);
}


5

কোডের নীচে ব্যবহার করুন, এটি দেখার আকার দেয়।

@Override
public void onWindowFocusChanged(boolean hasFocus) {
       super.onWindowFocusChanged(hasFocus);
       Log.e("WIDTH",""+view.getWidth());
       Log.e("HEIGHT",""+view.getHeight());
}

5

এটি আমার জন্য কাজ করে onClickListener:

yourView.postDelayed(new Runnable() {               
    @Override
    public void run() {         
        yourView.invalidate();
        System.out.println("Height yourView: " + yourView.getHeight());
        System.out.println("Width yourView: " + yourView.getWidth());               
    }
}, 1);

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

এই কোডটি ভুল। পরবর্তী দেরিতে পোস্ট দেরি গ্যারান্টি দেয় না আপনার ভিউ পরিমাপ করা হয়েছে।
ইয়ান ওয়াং

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

4

আমিও প্রায় হারিয়ে গেছে getMeasuredWidth()এবং getMeasuredHeight() getHeight()এবং getWidth()একটি দীর্ঘ সময়ের জন্য .......... পরে আমি দেখা গেছে যে দেখুন এর প্রস্থ ও উচ্চতা পেয়ে onSizeChanged()এই কাজ করতে সবচেয়ে ভাল উপায় ........ আপনি পরিবর্তনশীল করতে পারেন ওভাররাইড করে আপনার দৃশ্যের CURRENT প্রস্থ এবং CURRENT উচ্চতা পানonSizeChanged( ) পদ্ধতিটি ।

এটিতে একটি বিস্তৃত কোড স্নিপেট রয়েছে এটি একবার দেখতে চান। নতুন ব্লগ পোস্ট: অ্যান্ড্রয়েডে কাস্টমভিউয়ের প্রস্থ এবং উচ্চতার মাত্রাগুলি (দেখুন প্রসারিত) কীভাবে পাবেন http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-ight-dimension.html


0

আপনি পর্দায় দৃশ্যের অবস্থান এবং মাত্রা উভয়ই পেতে পারেন

 val viewTreeObserver: ViewTreeObserver = videoView.viewTreeObserver;

if (viewTreeObserver.isAlive) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            //Remove Listener
            videoView.viewTreeObserver.removeOnGlobalLayoutListener(this);

            //View Dimentions
            viewWidth = videoView.width;
            viewHeight = videoView.height;

            //View Location
            val point = IntArray(2)
            videoView.post {
                videoView.getLocationOnScreen(point) // or getLocationInWindow(point)
                viewPositionX = point[0]
                viewPositionY = point[1]
            }

        }
    });
}

-1

আমার জন্য পারফেক্ট কাজ করে:

 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        CTEditor ctEdit = Element as CTEditor;
        if (ctEdit == null) return;           
        if (e.PropertyName == "Text")
        {
            double xHeight = Element.Height;
            double aHaight = Control.Height;
            double height;                
            Control.Measure(LayoutParams.MatchParent,LayoutParams.WrapContent);
            height = Control.MeasuredHeight;
            height = xHeight / aHaight * height;
            if (Element.HeightRequest != height)
                Element.HeightRequest = height;
        }
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.