2010-01-16 19 views
23

मैं एंड्रॉइड के लिए नया हूं।Android में आसानी से कैनवास स्क्रॉल करना

मैं अपने दृश्य के ऑनड्रा (कैनवास कैनवास) विधि के अंदर कैनवास पर बिटमैप्स, रेखाएं और आकार खींच रहा हूं। मैं उपयोगकर्ता द्वारा ड्रैग के जवाब में चिकनी स्क्रॉलिंग को कार्यान्वित करने के तरीके पर सहायता की तलाश में हूं। मैंने खोज की है लेकिन मुझे इसके साथ मदद करने के लिए कोई ट्यूटोरियल नहीं मिला है।

कैनवास के संदर्भ में ऐसा लगता है कि यदि एक कैनवास को बिटमैप (जिसे बीएमपीबफर कहा जाता है) से बनाया गया है तो कैनवास पर खींचा गया कुछ भी बीएमपीबफर पर खींचा जाता है। क्या स्क्रॉल को लागू करने के लिए bmpbuffer का उपयोग करना संभव होगा ... शायद इसे एक समय में कुछ पिक्सल द्वारा स्थानांतरित कैनवास पर कॉपी करें? लेकिन अगर मैं कुछ पिक्सल द्वारा कैनवास में स्थानांतरित करने के लिए bmpBuffer को वापस खींचने के लिए Canvas.drawBitmap का उपयोग करता हूं, तो bmpBuffer दूषित नहीं होगा? शायद, इसलिए, मुझे bmpbuffer को bmpBuffer2 पर प्रतिलिपि बनाना चाहिए, फिर bmpBuffer2 को कैनवास पर वापस खींचें।

लाइनों, आकृतियों, इत्यादि को सीधे एक बफर बिटमैप में खींचने के लिए एक और सीधा दृष्टिकोण होगा, फिर उस बफर को (एक शिफ्ट के साथ) कैनवास पर खींचें, लेकिन जहां तक ​​मैं विभिन्न विधियों को देख सकता हूं: drawLine() , drawShape() और इतने पर बिटमैप पर ड्राइंग के लिए उपलब्ध नहीं हैं ... केवल कैनवास के लिए।

क्या मेरे पास 2 कैनवास हो सकते हैं? इनमें से एक बफर बिटमैप से बनाया जाएगा और लाइनों, आकृतियों इत्यादि की साजिश के लिए बस इस्तेमाल किया जाएगा और फिर बफर बिटमैप दृश्य में प्रदर्शन के लिए अन्य कैनवास पर खींचा जाएगा?

मुझे किसी भी सलाह का स्वागत करना चाहिए!

यहां समान प्रश्नों के उत्तर (और अन्य वेबसाइटों पर) "ब्लिटिंग" का संदर्भ लें। मैं अवधारणा को समझता हूं लेकिन एंड्रॉइड प्रलेखन में "ब्लिट" या "बिटब्लैट" के बारे में कुछ भी नहीं मिला। Canvas.drawBitmap और बिटमैप हैं। एंड्रॉइड के समकक्ष कॉपी करें?

+0

में थोड़ा और अधिक आज सुबह googling किया। इस वेब पेज के अनुसार http://markmail.org/message/oedvjxi3dhokzq23 मेरे पास दूसरा कैनवास हो सकता है, इसलिए मैं उस विचार का पता लगाऊंगा। – prepbgg

+0

इसके बारे में नीचे एक नए "उत्तर" में और देखें। – prepbgg

उत्तर

1

मैं भी इस समस्या थी,

मैं इस तरह ड्राइंग था:

Canvas BigCanvas = new Canvas(); 
Bitmap BigBitmap = new Bitmap(width,height); 

int ScrollPosX , ScrollPosY // (calculate these with the onScrollEvent handler) 

void onCreate() 
{ 
    BigCanvas.SetBitmap(BigBitmap); 
} 

onDraw(Canvas TargetCanvas) 
{ 
    // do drawing stuff 
    // ie. BigCanvas.Draw.... line/bitmap/anything 

    //draw to the screen with the scrolloffset 

    //drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint) 
    TargetCanvas.DrawBitmap(BigBitmap(new Rect(ScrollPosX,ScrollPosY,ScrollPosX + BigBitmap.getWidth(),ScrollPosY + BigBitmap.getHeight(),new Rect(0,0,ScreenWidth,ScreenHeight),null); 
} 
चिकनी के लिए

स्क्रॉल आप विधि है कि स्क्रॉल के बाद कुछ अंक लेता है किसी प्रकार का बनाने के लिए आवश्यकता होगी (यानी पहला स्क्रॉल पॉइंट और 10 वां), उन घटकों को घटाएं और उस लूप को प्रत्येक लूप के लिए स्क्रॉल करें जो इसे धीरे-धीरे धीमा कर देता है (स्क्रॉलअमाउंट - मोड़ - घर्षण)।

मुझे आशा है कि इससे कुछ और अंतर्दृष्टि मिलती है।

+0

धन्यवाद, मॉर्विन, आपके उत्तर के लिए । मुझे यकीन नहीं है कि मैं समझता हूं कि आपकी स्क्रॉलिंग कैसे काम करती है। क्या आप बिटमैप को स्थानांतरित करने से पहले 10 स्क्रॉल ईवेंट प्राप्त होने तक प्रतीक्षा करते हैं? मैंने कल्पना की थी कि, स्क्रीन डिस्प्ले को पूरी तरह उत्तरदायी बनाने के लिए मुझे पहली स्क्रॉल ईवेंट प्राप्त होने के बाद कैनवास पर बिटमैप को फिर से निकालना होगा। और, क्योंकि मेरी "ड्राइंग स्टफ" काफी समय लेने वाली है, इसलिए मैंने इस कार्यक्रम को स्क्रॉल के लिए यथासंभव उत्तरदायी बनाने के प्रयास में ऑन ड्रा विधि से बाहर ले जाने का निर्णय लिया। – prepbgg

12

मुझे लगता है कि मुझे कोई जवाब मिल गया है। मैंने एक नई डू ड्रॉइंग() विधि में ड्रॉइंग कोड का बड़ा हिस्सा रखा है (जो पहले ड्रॉ() में था)। यह विधि स्क्रीन से बड़ा एक नया बिटमैप बनाकर शुरू होती है (पूर्ण ड्राइंग को पकड़ने के लिए पर्याप्त बड़ा)।

BufferBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888); 
    Canvas BufferCanvas = new Canvas(BufferBitmap); 

विधि doDrawing() के बाकी BufferCanvas करने के लिए विस्तृत चित्र के साथ लिया जाता है: यह तो एक दूसरी कैनवास जिस पर विस्तृत ड्राइंग करने के लिए बनाता है।

@Override protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.drawBitmap(BufferBitmap, (float) -posX, (float) -posY, null); 
} 

स्थिति चर, posX और कहावत, आवेदन की OnCreate() विधि में 0 पर initialised कर रहे हैं:

पूरे OnDraw() विधि अब के रूप में पढ़ता। एप्लिकेशन OnGestureListener लागू करता है और posX और posY को बढ़ाने के लिए ऑनस्क्रॉल अधिसूचना में वापस आया दूरी और दूरी वाई तर्क का उपयोग करता है।

ऐसा लगता है कि चिकनी स्क्रॉलिंग को लागू करने के लिए आवश्यक सभी चीजों के बारे में ऐसा लगता है। या मैं कुछ देख रहा हूँ !?

+0

एक "चीज" लिखने के बाद से मैंने जो खोजा है, वह यह है कि स्क्रीन घुमाए जाने पर बफर बिटमैप (और किसी अन्य बिटमैप ऑब्जेक्ट्स) को "रीसायकल" करने के लिए अतिरिक्त कोड की आवश्यकता होती है। ऐसा इसलिए है क्योंकि जब स्क्रीन घुमाया जाता है तो ऐप की मुख्य गतिविधि समाप्त हो जाती है और फिर से शुरू होती है लेकिन बिटमैप ऑब्जेक्ट्स द्वारा उपयोग की जाने वाली मेमोरी स्वचालित रूप से सिस्टम द्वारा पुनर्प्राप्त नहीं होती है। इसलिए, जब यह अब आवश्यक नहीं है, तो प्रत्येक बिटमैप के लिए रीसायकल() विधि को कॉल करना महत्वपूर्ण लगता है। बफर बिटमैप के मामले में उत्तर गतिविधि की ऑनस्ट्राय विधि को ओवरराइड करना और बिटमैप के रीसायकल() को कॉल करना प्रतीत होता है। – prepbgg

+0

मैनिफेस्ट में 'एंड्रॉइड: configChanges = "ओरिएंटेशन" डालने से यह कोड टाला जा सकता है।2011-01-04 के इस प्रश्न के लिए रिबो का जवाब देखें। – prepbgg

+0

कृपया इस प्रश्न में सहायता करें http://stackoverflow.com/questions/11720702/canvas-zoom-in-partially/11721193#11721193 –

0

prepbgg: मुझे नहीं लगता कि कोड काम करेगा क्योंकि canvas.drawBitmap बिटमैप में नहीं आता है लेकिन कैनवास पर बिटमैप खींचता है।

अगर मैं गलत हूं तो मुझे सुधारें!

+0

धन्यवाद, मास्टरगोराव। मैं सहमत हूं कि canvas.drawBitmap (BufferBitmap, ...) BufferBitmap में कुछ भी नहीं खींचता है। हालांकि, मेरे पास एक अलग डू ड्रॉइंग() विधि है जहां चीजें (रेखाएं, बिटमैप्स इत्यादि) को बफरकैनवास में खींचा जाता है और इस प्रकार बफर बिटमैप में होता है। कोड काम करता प्रतीत होता है (हालांकि यह कभी-कभी स्टटर और/या क्रैश करता है ... मुझे नहीं पता कि ऐसा इसलिए है क्योंकि मेरा ड्राइंग कोड दोषपूर्ण है या क्या अन्य त्रुटियां हैं।) – prepbgg

1

गतिविधि को पुनरारंभ करने की कोई आवश्यकता नहीं है! (प्रीपेग के 27 जनवरी 10 को उनके जनवरी 17 10 'उत्तर' के जवाब में) बिटमैप को रीसाइक्लिंग करने और गतिविधि को फिर से लोड करने के ऊपरी हिस्से को बढ़ाने के बजाय, आप नीचे दिखाए गए 'एंड्रॉइड: configChanges' विशेषता को डालकर एप्लिकेशन को लोड करने से बच सकते हैं, ऐप के लिए AndroidManifest.xml फ़ाइल के 'गतिविधि' तत्व में। यह सिस्टम को बताता है कि ऐप अभिविन्यास परिवर्तनों को संभालेगा और उसे ऐप को पुनरारंभ करने की आवश्यकता नहीं है।

<activity android:name=".ANote" 
    android:label="@string/app_name" 
    android:configChanges="orientation|screenLayout"> 
    <intent-filter> 
     <action android:name="android.intent.action.MAIN" /> 
     <category android:name="android.intent.category.LAUNCHER" /> 
    </intent-filter> 
</activity> 

इस विधि जब orienation बदल गया है एक अधिसूचना प्राप्त करने के लिए इस्तेमाल किया जा सकता:

public void onConfigurationChanged(Configuration newConfig) { 
    super.onConfigurationChanged(newConfig); 
    prt("onConfigurationChanged: "+newConfig); 

    if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { 
     prt(" PORTRAIT"); 
    } else { 
     prt(" LANDSCAPE"); 
    } 
} // end of onConfigurationChanged 
+0

यह बहुत दिलचस्प है। (वास्तव में, मैंने काफी शुरुआती चरण में ऐप को एंड्रॉइड डालने से अभिविन्यास बदलना बंद कर दिया: स्क्रीनऑरिएंटेशन = "पोर्ट्रेट" मैनिफेस्ट में। मैंने स्मृति समस्याओं को रोकने के लिए ऐसा किया।) हालांकि, मैं रोटेशन को संभालना चाहता हूं मुमकिन। जब आप एप हैंडलिंग अभिविन्यास परिवर्तनों की बात करते हैं, तो इसे प्राप्त करने के लिए मुझे क्या करने की ज़रूरत है? क्या व्यू की ऑन ड्रा विधि अभी भी स्वचालित रूप से कॉल की जाएगी? या क्या मैं बस, दृश्य को "अमान्य" करके रोटेशन का जवाब देता हूं? – prepbgg

+0

मैंने अभी एंड्रॉइड: स्क्रीनऑरिएंटेशन = "पोर्ट्रेट" को एंड्रॉइड के साथ मैनिफेस्ट में बदल दिया है: configChanges = "orientation" 'और ऐप बस काम करता है! (अभिविन्यास परिवर्तन की जांच करने के लिए कोई कोड रखने की आवश्यकता नहीं है ... स्क्रीन मुझसे किसी भी हस्तक्षेप के बिना फिर से खींची जाती है।) लॉगकैट सुझाव देता है कि प्रत्येक बार अभिविन्यास बदल जाने पर फोन कचरा संग्रहण में लगभग 250 मीटर खर्च करता है। मैं अभी तक कोई समस्या नहीं देख सकता। इस सुझाव के साथ यहां आने के लिए बहुत बहुत धन्यवाद। – prepbgg

1

विक्टर के जवाब की निरंतरता ...

वास्तव में, स्थिति और अधिक जटिल है। चूंकि डूड्रॉइंग प्रक्रिया काफी धीमी है (मेरे धीमे पुराने एचटीसी हीरो फोन पर 2-3 सेकंड लेना) मुझे यह पता लगाने के लिए एक टोस्ट संदेश पॉप अप करना वांछनीय लगता है कि यह हो रहा था और कारण बताता है। यह करने के लिए स्पष्ट तरीका है एक नई पद्धति सिर्फ 2 लाइनों युक्त बनाने के लिए किया गया था:

public void redrawBuffer(String strReason) { 
    Toaster.Toast(strReason, "Short");` 
    doDrawing(); 
} 

और doDrawing के बजाय मेरा कार्यक्रम में अन्य स्थानों से इस विधि कॉल करने के()।

हालांकि, मैंने पाया कि टोस्टर या तो कभी प्रकट नहीं हुआ या इतनी संक्षेप में चमक नहीं आया कि इसे पढ़ा नहीं जा सका। मेरा कामकाज टोस्ट को प्रदर्शित करने और डूडिंग() को कॉल करने के बीच 200 मिलीसेकंड के लिए सोने के लिए मजबूर करने के लिए एक समय चेक हैंडलर का उपयोग करना है। यद्यपि यह थोड़ा सा रेड्रा की शुरुआत में देरी करता है, मुझे लगता है कि यह प्रोग्राम की प्रयोज्यता के मामले में भुगतान करने योग्य मूल्य है क्योंकि उपयोगकर्ता जानता है कि क्या हो रहा है। reDrawBuffer() अब पढ़ता है:

public void redrawBuffer(String strReason) { 
    Toaster.Toast(strReason, "Short"); 
    mTimeCheckHandler.sleep(200);  
}` 

और हैंडलर कोड (जो मेरे दृश्य वर्ग के भीतर नीडिंत है) है:

private timeCheckHandler mTimeCheckHandler = new timeCheckHandler(); 

class timeCheckHandler extends Handler { 
@Override 
    public void handleMessage(Message msg) { 
     doDrawing(); 
    } 
    public void sleep(long delayMillis) { 
     this.removeMessages(0); 
     sendMessageDelayed(obtainMessage(0), delayMillis); 
    } 
}` 
संबंधित मुद्दे