अपना स्वयं का दृश्य घटक बनाने का एक व्यावहारिक उदाहरण

अपना स्वयं का दृश्य घटक बनाने का एक व्यावहारिक उदाहरण


मुझे ड्रिबल पसंद है। कई शांत और प्रेरणादायक डिजाइन परियोजनाएं हैं। लेकिन अगर आप एक डेवलपर हैं, तो अक्सर सुंदरता की भावना निराशा से बदल जाती है जब आप इस शांत डिजाइन को लागू करने के बारे में सोचना शुरू करते हैं।


इस लेख में मैं आपको इस तरह के एक डिजाइन और इसके कार्यान्वयन का एक उदाहरण दिखाऊंगा, लेकिन इससे पहले, आइए समग्र रूप से समस्या को हल करने के बारे में बात करें।


सबसे आसान तरीका है कि किसी तरह के पुस्तकालय का उपयोग किया जाए जो हमारी जरूरतों को पूरा करता है। अब मुझे गलत मत समझो, मैं "पहिया को सुदृढ़ नहीं करता" दृष्टिकोण का एक बड़ा समर्थक हूं। महान खुले स्रोत पुस्तकालय हैं, और जब मुझे चित्र अपलोड करने या REST API, Glide / Picasso और Retrofit को लागू करने की आवश्यकता होती है, तो इससे मुझे बहुत मदद मिलेगी।


लेकिन जब आपको कुछ असामान्य डिजाइन लागू करने की आवश्यकता होती है, तो यह हमेशा सबसे अच्छा विकल्प नहीं होता है। आपको एक अच्छे, समर्थित पुस्तकालय की तलाश में समय बिताना होगा जो कुछ ऐसा ही करेगा। फिर आपको यह सुनिश्चित करने के लिए कोड पर गौर करने की आवश्यकता है कि वहां कुछ पर्याप्त लिखा गया है। आपको अपने कार्यों में लाइब्रेरी का उपयोग करने के लिए प्रबंधित की जाने वाली सेटिंग्स और कॉन्फ़िगरेशन को समझने के लिए अधिक समय समर्पित करने की आवश्यकता होगी। और चलो ईमानदार रहें, सबसे अधिक संभावना है, पुस्तकालय आपकी आवश्यकताओं को 100% कवर नहीं करेगा, और आपको डिजाइनरों के साथ कुछ समझौता करने की आवश्यकता होगी।


इसलिए, मैं कहता हूं कि अपना स्वयं का View कंपोनेंट बनाना अक्सर आसान और बेहतर होता है। जब मैं कहता हूं "मूल View घटक", मेरा मतलब है View वर्ग का विस्तार, onDraw() विधि को ओवरराइड करना और View घटक को आकर्षित करने के लिए Paint और Canvas का उपयोग करना। यह डरावना हो सकता है यदि आपने इसे पहले नहीं किया है, क्योंकि इन वर्गों में कई विधियां और गुण हैं, लेकिन आप मुख्य तरीकों पर ध्यान केंद्रित कर सकते हैं:


  • canvas.drawRect() - कोनों के निर्देशांक निर्दिष्ट करें और एक आयत canvas.drawRect() ;


  • canvas.drawRoundRect() - वैकल्पिक रूप से त्रिज्या निर्दिष्ट करें, और आयत के कोनों को गोल किया जाएगा;


  • canvas.drawPath() एक अधिक जटिल है, लेकिन लाइनों और घटता का उपयोग करके अपना खुद का आकार बनाने के लिए और भी अधिक शक्तिशाली तरीका है;


  • canvas.drawText() - कैनवास पर पाठ खींचने के लिए ( Paint का उपयोग करके आप आकार, रंग और अन्य गुणों को नियंत्रित कर सकते हैं);


  • canvas.drawCircle() - केंद्र बिंदु और त्रिज्या निर्दिष्ट करें और एक सर्कल प्राप्त करें;


  • canvas.drawArc() - बाउंडिंग आयत निर्दिष्ट करें, साथ ही साथ आर्क ड्राइंग के लिए शुरुआती और मोड़ कोण;


  • paint.style - इंगित करता है कि क्या खींची गई आकृति को भरा जाएगा, चक्कर लगाया जाएगा, या दोनों;


  • paint.color । रंग - रंग इंगित करता है (पारदर्शिता सहित);


  • paint.strokeWidth - स्ट्रोक आकृतियों के लिए चौड़ाई को नियंत्रित करता है;


  • paint.pathEffect - आपको खींची गई आकृति की ज्यामिति को प्रभावित करने की अनुमति देता है;


  • paint.shader - आपको ग्रेडिएंट आकर्षित करने की अनुमति देता है।



याद रखें, कभी-कभी आपको अन्य एपीआई का उपयोग करने की आवश्यकता हो सकती है, लेकिन यहां तक ​​कि इन विधियों में महारत हासिल करने के बाद, आप बहुत ही जटिल आकृतियों को आकर्षित कर सकते हैं।


व्यावहारिक उदाहरण


यहाँ एक डिजाइन है काली मिर्च हमें प्रदान करता है:


डिज़ाइन


यहां कई दिलचस्प चीजें हैं, लेकिन चलो इसे सभी छोटे टुकड़ों में लेते हैं।


चरण 1. मार्कर पदों की गणना करें


 private fun calcPositions(markers: List<Marker>) { val max = markers.maxBy { it.value } val min = markers.minBy { it.value } pxPerUnit = chartHeight / (max - min) zeroY = max * pxPerUnit + paddingTop val step = (width - 2 * padding - scalesWidth) / (markers.size - 1) for ((i, marker) in markers.withIndex()) { val x = step * i + paddingLeft val y = zeroY - entry.value * pxPerUnit marker.currentPos.x = x marker.currentPos.y = y } } 

हम न्यूनतम और अधिकतम मान पाते हैं, प्रति इकाई पिक्सेल के अनुपात की गणना करते हैं, मार्करों और एक्स और वाई पदों के बीच क्षैतिज चरण का आकार।


चरण 2. एक ढाल बनाएं


ढाल


 // prepare the gradient paint val colors = intArrayOf(colorStart, colorEnd)) val gradient = LinearGradient( 0f, paddingTop, 0f, zeroY, colors, null, CLAMP ) gradientPaint.style = FILL gradientPaint.shader = gradient private fun drawGradient(canvas: Canvas) { path.reset() path.moveTo(paddingLeft, zeroY) for (marker in markers) { path.lineTo(marker.targetPos.x, entry.targetPos.y) } // close the path path.lineTo(markers.last().targetPos.x, zeroY) path.lineTo(paddingLeft, zeroY) canvas.drawPath(path, gradientPaint) } 

हम बाएं किनारे से शुरू होने वाले आकार बनाते हैं, प्रत्येक मार्कर के बीच एक रेखा खींचते हैं और प्रारंभिक बिंदु पर आकार को समाप्त करते हैं। फिर एक ढाल ढाल के साथ पेंट का उपयोग करके इस आकृति को बनाएं।


चरण 3. एक ग्रिड बनाएं


जाल


 // prepare the guideline paint dottedPaint.style = STROKE dottedPaint.strokeWidth = DOTTED_STROKE_WIDTH_DP dottedPaint.pathEffect = DashPathEffect(floatArrayOf(INTERVAL, INTERVAL), 0f) private fun drawGuidelines(canvas: Canvas) { val first = findFirstDayOfWeekInMonth(markers) for (i in first..markers.lastIndex step 7) { val marker = markers[i] guidelinePath.reset() guidelinePath.moveTo(entry.currentPos.x, paddingTop) guidelinePath.lineTo(entry.currentPos.x, zeroY) canvas.drawPath(guidelinePath, dottedPaint) } } 

हम पेंट सेट करते हैं ताकि यह एक बिंदीदार रेखा के साथ आकर्षित हो। फिर हम विशेष कोटलिन भाषा चक्र का उपयोग करते हैं, जो हमें मार्करों पर 7 (एक सप्ताह में दिनों की संख्या) के चरणों में पुनरावृति करने की अनुमति देता है। प्रत्येक मार्कर के लिए, हम एक्स कोऑर्डिनेट करते हैं और ग्राफ के ऊपर से zeroY तक एक ऊर्ध्वाधर बिंदीदार रेखा zeroY


चरण 4. एक ग्राफ और मार्करों को ड्रा करें


चार्ट और मार्कर


 private fun drawLineAndMarkers(canvas: Canvas) { var previousMarker: Marker? = null for (marker in markers) { if (previousMarker != null) { // draw the line val p1 = previousMarker.currentPos val p2 = marker.currentPos canvas.drawLine(p1.x, p1.y, p2.x, p2.y, strokePaint) } previousMarker = marker // draw the marker canvas.drawCircle( marker.currentPos.x, marker.currentPos.y, pointRadius, pointPaint ) } } 

हम मार्करों के माध्यम से जाते हैं, उनमें से प्रत्येक के लिए एक भरा हुआ वृत्त खींचते हैं और पिछले मार्कर से एक वर्तमान तक एक सरल रेखा बनाते हैं।


चरण 5. सप्ताह बटन खींचें


सप्ताह बटन


 private fun drawWeeks(canvas: Canvas) { for ((i, week) in weeks.withIndex()) { textPaint.getTextBounds(week, 0, week.length, rect) val x = middle(i) val y = zeroY + rect.height() val halfWidth = rect.width() / 2f val halfHeight = rect.height() / 2f val left = x - halfWidth - padding val top = y - halfHeight - padding val right = x + halfWidth + padding val bottom = y + halfHeight + padding rect.set(left, top, right, bottom) paint.color = bgColor paint.style = FILL canvas.drawRoundRect(rect, radius, radius, paint) paint.color = strokeColor paint.style = STROKE canvas.drawRoundRect(rect, radius, radius, paint) canvas.drawText(week, x, keyY, textPaint) } } 

हम सप्ताह के निशान पर जाते हैं, सप्ताह के मध्य के एक्स समन्वय को पाते हैं और परतों में बटन खींचना शुरू करते हैं: पहले हम गोल कोनों के साथ एक पृष्ठभूमि खींचते हैं, फिर एक सीमा और आखिरकार, पाठ। हम प्रत्येक परत को चित्रित करने से पहले पेंट को समायोजित करते हैं।


चरण 6. दाईं ओर संख्यात्मक मार्कर ड्रा करें


न्यूमेरिक मार्कर


 private fun drawGraduations(canvas: Canvas) { val x = markers.last().currentPos.x + padding for (value in graduations) { val y = zeroY - scale * pxPerUnit val formatted = NumberFormat.getIntegerInstance().format(value) canvas.drawText(formatted, x, y, textPaint) } } 

X निर्देशांक अंतिम मार्कर की स्थिति है और कुछ इंडेंटेशन। Y निर्देशांक की गणना प्रति इकाई पिक्सेल के अनुपात का उपयोग करके की जाती है। हम संख्या को एक स्ट्रिंग में प्रारूपित करते हैं (यदि आवश्यक हो, एक हजारों विभाजक जोड़ें) और पाठ आकर्षित करें।


बस इतना ही, अब हमारा onDraw() इस तरह दिखेगा:


 override fun onDraw(canvas: Canvas) { drawGradient(canvas) drawGuidelines(canvas) drawLineAndMarkers(canvas) drawWeeks(canvas) drawGraduations(canvas) } 

और परतों के संयोजन से हमें वांछित परिणाम मिलेगा:


परिणाम


परिणाम


  1. अपने स्वयं के View घटकों (यदि आवश्यक हो) बनाने से डरो मत।
  2. मूल Canvas और Paint एपीआई जानें।
  3. अपने डिजाइन को छोटी परतों में तोड़ें और प्रत्येक को स्वतंत्र रूप से खींचें।

अंतिम बिंदु के रूप में, मेरे लिए यह सामान्य रूप से सबसे अच्छा प्रोग्रामिंग सबक में से एक है: जब एक बड़े और जटिल कार्य के साथ सामना किया जाता है, तो इसे छोटे, सरल कार्यों में तोड़ दें।

Source: https://habr.com/ru/post/hi433782/


All Articles