किसी दृश्य के पूर्ण निर्देशांक कैसे प्राप्त करें


390

मैं एक दृश्य के ऊपरी बाएँ कोने के निरपेक्ष स्क्रीन पिक्सेल निर्देशांक प्राप्त करने की कोशिश कर रहा हूँ। हालाँकि, सभी विधियाँ मैं ऐसे ढूँढ सकता हूँ getLeft()और getRight()काम नहीं कर सकता क्योंकि वे सभी दृश्य के जनक के सापेक्ष प्रतीत होती हैं, इस प्रकार मुझे दे रही हैं 0। ऐसा करने का उचित तरीका क्या है?

यदि यह मदद करता है, तो यह 'तस्वीर को वापस क्रम में लाने के लिए' खेल के लिए है। मैं चाहता हूं कि उपयोगकर्ता कई टुकड़ों का चयन करने के लिए एक बॉक्स बनाने में सक्षम हो। मेरे इस धारणा है कि करने के लिए है कि क्या करने के लिए सबसे आसान तरीका है getRawX()और getRawY()से MotionEventऔर फिर लेआउट टुकड़े धारण के ऊपरी बाएं कोने के खिलाफ उन मूल्यों की तुलना करें। टुकड़ों के आकार को जानने के बाद, मैं यह निर्धारित कर सकता हूं कि कितने टुकड़ों का चयन किया गया है। मुझे लगता है कि मैं उपयोग कर सकता हूं getX()और getY()पर MotionEvent, लेकिन जैसा कि एक सापेक्ष स्थिति देता है जो यह निर्धारित करता है कि कौन से टुकड़े अधिक कठिन चुने गए थे। (असंभव नहीं, मुझे पता है, लेकिन यह अनावश्यक रूप से जटिल लगता है)।

संपादित करें: यह वह कोड है जिसका उपयोग मैंने एक प्रश्न के अनुसार होल्डिंग कंटेनर के आकार को प्राप्त करने के लिए किया था। TableLayoutवह मेज है जो सभी पहेली टुकड़े रखती है।

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft());

संपादित 2: यहाँ सुझाए गए उत्तरों का अधिक पालन करते हुए कोड मैंने कोशिश की है।

public int[] tableLayoutCorners = new int[2];
(...)

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
tableLayout.requestLayout();
Rect corners = new Rect();
tableLayout.getLocalVisibleRect(corners);
Log.d(LOG_TAG, "Top left " + corners.top + ", " + corners.left + ", " + corners.right
            + ", " + corners.bottom);

cells[4].getLocationOnScreen(tableLayoutCorners);
Log.d(LOG_TAG, "Values " + tableLayoutCorners[0] + ", " + tableLayoutCorners[1]);

यह कोड सभी इनिशियलाइजेशन के होने के बाद जोड़ा गया था। छवि को ImageViews (कक्षों [] सरणी) के एक सरणी में विभाजित किया गया है, जिसमें निहित है a TableLayout। कक्ष [0] शीर्ष बाएं है ImageView, और मैंने कोशिकाओं को चुना [4] क्योंकि यह बीच में कहीं है और निश्चित रूप से (0,0) के निर्देशांक नहीं होने चाहिए।

ऊपर दिखाया गया कोड मुझे अभी भी लॉग में सभी 0s देता है, जो मुझे वास्तव में समझ में नहीं आता है क्योंकि विभिन्न पहेली टुकड़े सही ढंग से प्रदर्शित होते हैं। (मैंने टेबल लाइटर कॉर्नर और डिफ़ॉल्ट दृश्यता के लिए सार्वजनिक रूप से प्रयास किया, दोनों एक ही परिणाम दे रहे हैं।)

मुझे नहीं पता कि यह महत्वपूर्ण है, लेकिन ImageViewमूल रूप से एस को आकार नहीं दिया जाता है। ImageViewजब मैं इसे प्रदर्शित करने के लिए एक छवि देता हूं , तो एस का आकार स्वचालित रूप से दृश्य द्वारा आरंभ के दौरान निर्धारित किया जाता है। क्या यह उनके मान 0 में योगदान दे सकता है, भले ही वह लॉगिंग कोड है क्योंकि उन्हें एक छवि दी गई है और स्वचालित रूप से अपने आप को फिर से आकार दिया है? संभावित रूप से काउंटर करने के लिए, मैंने tableLayout.requestLayout()ऊपर दिखाए अनुसार कोड जोड़ा , लेकिन इससे कोई मदद नहीं मिली।

जवाबों:


632

उपयोग View.getLocationOnScreen()और / या getLocationInWindow()


3
अब इस तरह के फंक्शन की मुझे उम्मीद है। दुर्भाग्य से, मुझे इसका ठीक से उपयोग नहीं करना चाहिए। मुझे पता है कि यह एक ज्ञात बग था कि getLocationOnScreen Android v1.5 (मैं जिस कोड के लिए कोडिंग कर रहा हूं) में एक शून्य सूचक अपवाद देता है, लेकिन v2.1 में परीक्षण किसी भी बेहतर काम नहीं किया। दोनों तरीकों ने मुझे हर चीज के लिए 0s दिया। मैंने ऊपर एक कोड स्निपेट शामिल किया।
स्टीव हेली

76
आप केवल इसे ले सकते हैं AFTER लेआउट हुआ है। स्क्रीन पर विचार पोस्ट किए जाने से पहले आप विधि को कॉल कर रहे हैं।
रोमेन गाइ

5
अहा, आप सही हैं हालांकि यह स्पष्ट नहीं था कि मैं ऐसा कर रहा था। धन्यवाद! अधिक विवरण के लिए उत्सुक किसी के लिए, मैंने एक उत्तर जोड़ा है जो बताता है कि मेरा क्या मतलब है।
स्टीव हेली

9
आप ViewTreeObserver और इसके OnGlobalLayoutListener की तरह मतलब है? आरंभ करने के लिए View.getViewTreeObserver () देखें।
रोमेन गाइ

8
@RomainGuy हाँ, इस तरह की तरह, लेकिन रजिस्टर (और फिर अपंजीकृत ...) होने की तुलना में कम भ्रामक। यह एक ऐसा क्षेत्र है जहां आईओएस एसडीके के मामले में एंड्रॉइड से बेहतर है। दैनिक आधार पर दोनों का उपयोग करते हुए, मैं कह सकता हूं कि आईओएस में बहुत सारी कष्टप्रद चीजें हैं, लेकिन यूआईवाइईई हैंडलिंग उनमें से एक नहीं है। :)
मार्टिन मार्कोसिनी

127

स्वीकृत उत्तर वास्तव में यह बताने के लिए नहीं था कि स्थान कैसे प्राप्त किया जाए, इसलिए यहां थोड़ा और विस्तार है। आप intलंबाई 2 की एक सरणी में पास करते हैं और मानों को व्यू (x, y) निर्देशांक (शीर्ष, बाएं कोने) से प्रतिस्थापित किया जाता है।

int[] location = new int[2];
myView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];

टिप्पणियाँ

  • जगह getLocationOnScreenके साथ getLocationInWindowज्यादातर मामलों में एक ही परिणाम देना चाहिए (देखें इस उत्तर )। हालाँकि, यदि आप डायलॉग या कस्टम कीबोर्ड जैसी छोटी विंडो में हैं, तो आपको यह चुनने की आवश्यकता होगी कि आपकी आवश्यकताओं में से कौन सा बेहतर है।
  • (0,0)यदि आप इस पद्धति को कॉल करते हैं तो आपको मिल जाएगा onCreateक्योंकि दृश्य अभी तक निर्धारित नहीं किया गया है। ViewTreeObserverजब लेआउट किया जाता है तो आप सुनने के लिए उपयोग कर सकते हैं और आप मापा निर्देशांक प्राप्त कर सकते हैं। ( इस उत्तर को देखें ।)

86

पहले आपको दृश्य की स्थानीय अदृश्य आयत प्राप्त करनी होगी

उदाहरण के लिए:

Rect rectf = new Rect();

//For coordinates location relative to the parent
anyView.getLocalVisibleRect(rectf);

//For coordinates location relative to the screen/display
anyView.getGlobalVisibleRect(rectf);

Log.d("WIDTH        :", String.valueOf(rectf.width()));
Log.d("HEIGHT       :", String.valueOf(rectf.height()));
Log.d("left         :", String.valueOf(rectf.left));
Log.d("right        :", String.valueOf(rectf.right));
Log.d("top          :", String.valueOf(rectf.top));
Log.d("bottom       :", String.valueOf(rectf.bottom));

आशा है कि यह मदद करेगा


3
यह भी काम किया जाना चाहिए ... हालांकि यह मुझे 0 के मान भी दे रहा है। मैंने ऊपर एक कोड स्निपेट शामिल किया है यदि आपको यह पता लगाने में मदद करता है कि मैंने क्या गलत किया। एक बार फिर धन्यवाद।
स्टीव हेली

1
मेरी अन्य टिप्पणियाँ देखें; इससे पहले कि मैं दृश्य को समाप्त कर रहा था, मैं खुद को गलती से बुला रहा था। यह अब ठीक काम करता है धन्यवाद।
स्टीव हेली

@ नवीन मूर्ति इसे विशिष्ट दृश्य के निर्देशांक देती है, मुझे रूट लेआउट में क्लिक किए गए दृश्य के निर्देशांक की आवश्यकता है ..
अनिकेत

20
यह माता-पिता के सापेक्ष स्थान लौटाता है। getGlobalVisibleRect()निरपेक्ष समन्वय के लिए उपयोग करें ।
जेफरी ब्लाॅटमैन

3
@SteveHaley, मैं उसी मुद्दे का सामना कर रहा हूं जैसा आपने किया था, किसी कारण से यह मुझे हर उस तरीके से 0 देता है जिसकी मैं कोशिश करता हूं। ऐसा लगता है कि आपने यह पता लगा लिया है कि यह शून्य क्यों दे रहा है। मैं लेआउट के लोड होने के बाद भी दृश्य के निर्देशांक प्राप्त करने की कोशिश कर रहा हूं मुझे शून्य मिलता है ऐसा क्यों है? आपकी मदद के लिए धन्यवाद
पंकज निमगडे

46

एक वैश्विक लेआउट श्रोता का उपयोग करना मेरे लिए हमेशा अच्छा रहा है। यदि लेआउट में बदलाव किया जाता है, तो चीजों को फिर से देखने में सक्षम होने का लाभ है, उदाहरण के लिए अगर कोई चीज View.GONE पर सेट है या बच्चे के विचार जोड़े / हटाए गए हैं।

public void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);

     // inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
     LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null); 

     // set a global layout listener which will be called when the layout pass is completed and the view is drawn
     mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
       new ViewTreeObserver.OnGlobalLayoutListener() {
          public void onGlobalLayout() {
               //Remove the listener before proceeding
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    mainLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
               } else {
                    mainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
               }

               // measure your views here
          }
       }
     );

     setContentView(mainLayout);
 }

OnGlobalLayoutListener को OnGlobalLayout () {...} के अंदर (अंत में) OnGlobalLayoutListener निकालना न भूलें। इसके अलावा, बस यह सुनिश्चित करने के लिए, जांचें कि क्या पारित हुआ है! = 0; श्रोता को दो बार बुलाया जा सकता है, एक बार w = 0 / h = 0 के मान के साथ, वास्तविक, सही, मान के साथ दूसरी बार।
मैक जूल

इस तरह से मुख्य लेआउट को फुलाया जाता है और फिर मेरे ऐप setContentView()में एक विशेष समस्या का कारण होता है Activity! यह एक संवाद गतिविधि ( windowFrame:@null, windowActionBar:false, windowIsFloating:true, windowNoTitle:true) थी। इसका मुख्य लेआउट (ए LinearLayout) निर्धारित layout_width( match_parentया उनमें से सभी wrap_content) के साथ कोई प्रत्यक्ष बच्चा नहीं है ।
मीर-इस्माइली

17

रोमेन गाइ की टिप्पणी के बाद, यहां बताया गया है कि मैंने इसे कैसे तय किया। उम्मीद है कि यह किसी और की भी मदद करेगा, जिसे यह समस्या थी।

मैं वास्तव में स्क्रीन पर रखी जाने से पहले विचारों की स्थिति को प्राप्त करने की कोशिश कर रहा था, लेकिन ऐसा बिल्कुल नहीं था। Initilisation कोड चलने के बाद उन लाइनों को रखा गया था, इसलिए मैंने माना कि सब कुछ तैयार था। हालाँकि, यह कोड अभी भी ऑनक्रिएट () में था; Thread.sleep () के साथ प्रयोग करके मैंने पाया कि लेआउट को वास्तव में तब तक अंतिम रूप नहीं दिया जाता है जब तक onCreate () के सभी रास्ते onResume () समाप्त नहीं हो जाते। इसलिए वास्तव में, कोड को लेआउट से पहले चलाने की कोशिश कर रहा था समाप्त होने के बाद स्क्रीन पर तैनात किया गया था। OnClickListener (या कुछ अन्य श्रोता) में कोड जोड़कर सही मान प्राप्त किए गए क्योंकि लेआउट समाप्त होने के बाद ही इसे निकाल दिया जा सकता था।


नीचे दी गई पंक्ति को एक समुदाय के रूप में सुझाया गया था:

इस्तेमाल करें onWindowfocuschanged(boolean hasFocus)


तो आपके कहने का मतलब है कि setContentView (my_layout); सभी विचारों को स्थान नहीं देगा। सभी विचारों को केवल onCreate () के समाप्त होने के बाद रखा जाएगा?
अश्विन

5
काफी नहीं। सभी दृश्य 'मौजूद' के बाद setContentView(R.layout.something), लेकिन वे नेत्रहीन लोड नहीं किए गए हैं। उनका आकार, या कोई पद नहीं है। यह तब तक नहीं होता है जब तक कि पहला लेआउट समाप्त नहीं हो जाता है, जो भविष्य में कुछ बिंदु पर होता है (आमतौर पर onResume ())।
स्टीव हेली

14

पहला तरीका:

में Kotlin हम दृश्य के लिए एक सरल विस्तार बना सकते हैं:

fun View.getLocationOnScreen(): Point
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return Point(location[0],location[1])
}

और बस निर्देशांक प्राप्त करें:

val location = yourView.getLocationOnScreen()
val absX = location.x
val absY = location.y

दूसरा तरीका:

दूसरा तरीका अधिक सरल है:

fun View.absX(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[0]
}

fun View.absY(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[1]
}

और बस पूर्ण एक्स view.absX()बी और वाई बाय मिलता हैview.absY()


6
आपके 1 नमूने के लिए एक छोटा संस्करण:val location = IntArray(2).apply(::getLocationOnScreen)
तुआन चौ

5

मेरे बर्तन दृश्य स्थान प्राप्त करने के लिए कार्य करते हैं, यह किसी Pointवस्तु को x valueऔर साथ लौटाएगाy value

public static Point getLocationOnScreen(View view){
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    return new Point(location[0], location[1]);
}

का उपयोग करते हुए

Point viewALocation = getLocationOnScreen(viewA);

5

आप का उपयोग करके getLocationOnScreen()या देखें के निर्देशांक प्राप्त कर सकते हैंgetLocationInWindow()

बाद में, xऔर yदृश्य के ऊपरी-बाएँ कोने होना चाहिए। यदि आपका रूट लेआउट स्क्रीन से छोटा है (जैसे डायलॉग में), तो getLocationInWindowइसके कंटेनर के सापेक्ष उपयोग करना पूरे स्क्रीन पर नहीं होगा।

जावा सॉल्यूशन

int[] point = new int[2];
view.getLocationOnScreen(point); // or getLocationInWindow(point)
int x = point[0];
int y = point[1];

नोट: यदि मान हमेशा 0 है, तो आप स्थान का अनुरोध करने से तुरंत पहले दृश्य बदल सकते हैं।

यह सुनिश्चित करने के लिए कि दृश्य के नए लेआउट का उपयोग करके गणना किए जाने के बाद दृश्य को अपडेट करने का मौका दिया गया है, अपना स्थान अनुरोध चलाएं view.post:

view.post(() -> {
    // Values should no longer be 0
    int[] point = new int[2];
    view.getLocationOnScreen(point); // or getLocationInWindow(point)
    int x = point[0];
    int y = point[1];
});

~~

कोटलिन समाधान

val point = IntArray(2)
view.getLocationOnScreen(point) // or getLocationInWindow(point)
val (x, y) = point

नोट: यदि मान हमेशा 0 है, तो आप स्थान का अनुरोध करने से तुरंत पहले दृश्य बदल सकते हैं।

यह सुनिश्चित करने के लिए कि दृश्य के नए लेआउट का उपयोग करके गणना किए जाने के बाद दृश्य को अपडेट करने का मौका दिया गया है, अपना स्थान अनुरोध चलाएं view.post:

view.post {
    // Values should no longer be 0
    val point = IntArray(2)
    view.getLocationOnScreen(point) // or getLocationInWindow(point)
    val (x, y) = point
}

मैं इसे संभालने के लिए एक एक्सटेंशन फ़ंक्शन बनाने की सलाह देता हूं:

// To use, call:
val (x, y) = view.screenLocation

val View.screenLocation get(): IntArray {
    val point = IntArray(2)
    getLocationOnScreen(point)
    return point
}

और अगर आपको विश्वसनीयता की आवश्यकता है, तो भी जोड़ें:

view.screenLocationSafe { x, y -> Log.d("", "Use $x and $y here") }

fun View.screenLocationSafe(callback: (Int, Int) -> Unit) {
    post {
        val (x, y) = screenLocation
        callback(x, y)
    }
}

0

सटीक X और Y कॉर्डिनेट खोजने के लिए इस कोड का उपयोग करें:

int[] array = new int[2];
ViewForWhichLocationIsToBeFound.getLocationOnScreen(array);
if (AppConstants.DEBUG)
    Log.d(AppConstants.TAG, "array  X = " + array[0] + ", Y = " + array[1]);
ViewWhichToBeMovedOnFoundLocation.setTranslationX(array[0] + 21);
ViewWhichToBeMovedOnFoundLocation.setTranslationY(array[1] - 165);

मैंने अपना दृष्टिकोण समायोजित करने के लिए कुछ मूल्यों को जोड़ा / घटाया है। कृपया इन पंक्तियों को पूरे दृश्य के बाद ही फुलाया जाए।


"मैंने अपना दृष्टिकोण समायोजित करने के लिए कुछ मूल्यों को जोड़ा / घटाया है।" क्यों??
टूलमेकर

मेरा मतलब है कि मेरी आवश्यकता (देखने का स्थान) के अनुसार, मैंने अपने दृष्टिकोण को समायोजित करने के लिए मूल्यों को जोड़ा और घटाया है।
तरुण

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]
                }

            }
        });
    }

0

बस उपरोक्त उत्तर के अलावा, इस सवाल के लिए कि आपको कहां और कब कॉल करना चाहिए getLocationOnScreen?

आप जिस भी दृश्य को प्राप्त करना चाहते हैं, उससे संबंधित किसी भी जानकारी में, यह केवल स्क्रीन पर देखने के बाद ही उपलब्ध होगा। आप इसे आसानी से अपना कोड डालकर कर सकते हैं जो इस के अंदर दृश्य निर्माण पर निर्भर है (view.post (Runnable)):

view.post(new Runnable() {
            @Override
            public void run() {

               // This code will run view created and rendered on screen

               // So as the answer to this question, you can put
               int[] location = new int[2];
               myView.getLocationOnScreen(location);
               int x = location[0];
               int y = location[1];
            }
        });  
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.