खरोंच से Android घटक

सभी को नमस्कार! समान कार्यक्रमों के सामान्य द्रव्यमान से बाहर खड़े होने के लिए अपने स्वयं के इंटरफ़ेस घटकों को बनाना अक्सर एक आवश्यकता होती है। यह लेख उदाहरण के रूप में टाइमर बटन का उपयोग करके एक सरल, गैर-मानक घटक बनाने के बारे में है।

स्थापना:

एक स्लाइडर बटन विकसित करें जो निम्नानुसार काम करता है: बाईं ओर एक आयताकार क्षेत्र, एक ब्लॉक है जिसमें एक शिफ्ट की दिशा दिखाई जाती है:

उपयोगकर्ता तीर को दबाता है और इसे दाईं ओर अनुवाद करता है, क्योंकि यह पीछे हटा दिया जाता है, तीर रंगीन वर्ग खींचता है:

जैसे ही उपयोगकर्ता ब्लॉक को रिलीज़ करता है, पूरी लाइन बाईं ओर चलती है और दिखाए गए सभी ब्लॉकों को छुपाती है। आखिरी ब्लॉक को छिपाने के बाद, एक प्रसारण संदेश उत्पन्न किया जाना चाहिए कि टेप पूरी तरह से छिपा हुआ है।

ट्रेनिंग

एक नया घटक बनाने के लिए, एक नई परियोजना बनाएं। अगला, "CustomButton" नाम के साथ एक नया वर्ग बनाएं, पूर्वज के रूप में "दृश्य" वर्ग का उपयोग करें। अगला, एक क्लास कंस्ट्रक्टर बनाएं और परिणामस्वरूप, हमारा भविष्य घटक जैसा दिखेगा:
package com.racckat.test_coponent; import android.content.Context; import android.util.AttributeSet; import android.view.View; public class CustomButton extends View { public CustomButton(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } } 

अब हम क्लास कोड लिखना शुरू करते हैं। इससे पहले कि आप कोड लिखना शुरू कर दें, एक रंगीन टेप की छवि को / Res / drawable-hdpi फ़ोल्डर में छोड़ दें। कंस्ट्रक्टर में, आपको पहले सभी ऑब्जेक्ट्स को इनिशियलाइज़ करना होगा और सभी प्रीसेट्स बनाने होंगे। हम निम्नलिखित करते हैं:
1 - मुख्य गतिविधि के संदर्भ में लिंक की प्रतिलिपि बनाएँ;
2 - रंगीन वर्गों द्वारा विभाजित तैयार खाली पट्टी को लोड करें;
3 - सतह पर ड्राइंग के लिए आवश्यक घटक को कॉन्फ़िगर करें /
 public CustomButton(Context context, AttributeSet attrs) { super(context, attrs); _Context = context; //   //   _BMP_line = BitmapFactory.decodeResource(getResources(),R.drawable.line); //   mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(16); mPaint.setColor(0xFFFFFFFF); mPaint.setStyle(Style.FILL); } 

कक्षा की शुरुआत में वस्तुओं को भी घोषित करें:
  private Paint mPaint; //   public Bitmap _BMP_line; //   Context _Context; //  

अब हमें घटक नौकरशाही का आकार घटाने की प्रक्रिया को फिर से परिभाषित करने की आवश्यकता है। मैंने विशेष रूप से घटक के लिए निरंतर आयाम बनाए (300 * 50) ताकि उदाहरण को जटिल न किया जा सके। प्रक्रिया इस तरह दिखाई देगी:
  @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(300, 50); } 

अब "onDraw" घटक को फिर से तैयार करने की प्रक्रिया को फिर से परिभाषित करें। इस प्रक्रिया को हर बार कहा जाता है जब घटक को फिर से तैयार करना आवश्यक होता है। प्रक्रिया इस तरह दिखाई देगी:
  @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0,0, 300, 50, mPaint); canvas.drawBitmap(_BMP_line, 0, 0,null); } 

हमारे नए घटक के लिए रिक्त तैयार है, आइए इसे मुख्य गतिविधि पर रखें। सबसे पहले, हम "LinearLayout1" नाम के तहत, नई LinearLayout को मुख्य सतह पर रखेंगे। इसके बाद, क्लास कंस्ट्रक्टर में, नए बटन के लिए एक क्लास बनाएं, एक कार्यान्वयन क्लास "LinearLayout1" बनाएं और बटन को सतह पर जोड़ें। गतिविधि वर्ग ऐसा दिखेगा:
 package com.racckat.test_coponent; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.widget.LinearLayout; public class MainActivity extends Activity { @SuppressLint("WrongCall") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LinearLayout _LL1 = (LinearLayout) findViewById(R.id.LinearLayout1); CustomButton _CB1 = new CustomButton(MainActivity.this, null); _LL1.addView(_CB1); } } 

यदि आप प्रोजेक्ट को निष्पादन पर चलाते हैं, तो डिवाइस (एमुलेटर) पर आपको कुछ इस तरह दिखाई देगा:


कार्यात्मक

अब हम एनीमेशन और बाहरी घटनाओं पर प्रतिक्रिया को लागू करना शुरू करते हैं। जब उपयोगकर्ता उस इंटरफ़ेस के घटक पर क्लिक करता है जिसका पूर्वज दृश्य है, तो घटनाएं स्वचालित रूप से उत्पन्न होती हैं, विशेष रूप से, आप घटक पर क्लिक करने के निर्देशांक और क्लिक करने के चरणों (क्लिक किए गए, चले गए, उदास) को ट्रैक कर सकते हैं। इसलिए, आपको बाहरी घटनाओं के लिए जिम्मेदार onTouchEvent प्रक्रिया को ओवरराइड करने की आवश्यकता है। प्रक्रिया में एक तर्क "मोशन इवेंट" है, इसमें वर्तमान घटना के सभी पैरामीटर शामिल हैं। हम इन मापदंडों को निम्नानुसार निकालते हैं:
  Float X=(Float)event.getX(); //   X Float Y=(Float)event.getY(); //   Y int Action=event.getAction(); //  

हम प्रक्रिया को निम्नलिखित रूप में लाते हैं:
  @Override public boolean onTouchEvent(MotionEvent event) { //    Float X=(Float)event.getX(); //   X Float Y=(Float)event.getY(); //   Y int Action=event.getAction(); //  if((Action==MotionEvent.ACTION_DOWN)&&(X<60)&&(_Last_Action==0)) { _Last_Action = 1; //  _X = 0; } if((Action==MotionEvent.ACTION_MOVE)&&(_Last_Action == 1)) { _X = (int) (X/60); if (_X>4) _X=4; //     ,    if (_X<0) _X=0; invalidate(); //    } if (Action==MotionEvent.ACTION_UP){ _Last_Action = 2; if (_X>0) MyTimer(); //   else _Last_Action = 0; } return true; } 

मैं प्रत्येक पंक्ति को चित्रित नहीं करूंगा, मैं केवल मुख्य विचार निर्धारित करूंगा। उपयोगकर्ता घटक के तीर पर क्लिक करता है, यह कार्रवाई चर _Last_Action = 1 में तय की गई है, हम यह भी तय करते हैं कि उपयोगकर्ता ने टेप से कोई पासा नहीं खींचा है - _X = 0. अगला, हम घटक पर उंगली के आंदोलन को ट्रैक करते हैं और गणना करते हैं कि स्क्रीन पर कितने क्यूब्स दिखाई देने चाहिए, इसके लिए हम _X की गणना करते हैं। । अमान्य () कमांड का उपयोग करके रिडरिंग किया जाता है। अंत में, हम उंगली रिलीज को ठीक करते हैं और टाइमर शुरू करते हैं यदि उपयोगकर्ता ने कम से कम एक डाई खींच लिया है। पट्टी को अपनी मूल स्थिति में तेजी से नहीं, बल्कि धीरे-धीरे लौटने के लिए एक टाइमर की आवश्यकता होती है।

अब हम टाइमर को स्वयं लागू करते हैं, जो पट्टी को उसकी मूल स्थिति में लौटा देगा। टाइमर कोड जैसा दिखेगा:
  //   public void MyTimer(){ Thread t = new Thread(new Runnable() { public void run() { for(;;){ try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) {e.printStackTrace();} _X--; myHandler.sendEmptyMessage(0); if (_X==0){//      myHandler.sendEmptyMessage(0); //   _Last_Action = 0; //     break; //    } } } }); t.start(); } 

इस प्रक्रिया में, वैरिएबल _X के मान को 1 से कम करने का कार्य चक्रीय है, जिससे पता चलता है कि घटक पर किस सेक्टर को प्रदर्शित किया जाना चाहिए। चूंकि आप अतिरिक्त थ्रेड से एक घटक की उपस्थिति को प्रभावित नहीं कर सकते हैं, इसलिए आपको हैंडल के माध्यम से रीड्रा संदेश भेजना होगा। इसलिए, क्लास कंस्ट्रक्टर में, हम हैंडल के लिए संदेश अवरोधन के कार्यान्वयन को जोड़ते हैं और विजेट की उपस्थिति को फिर से जोड़ते हैं:
  myHandler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what==0){ invalidate(); //    } } }; 

अब यह विजेट को फिर से व्यवस्थित करने की प्रक्रिया को बदलने के लिए बना हुआ है, अर्थात् सतह पर रिबन की स्थिति के लिए लाइन (रिबन पर एक छोटे वर्ग की चौड़ाई 60 पिक्स है, और कुल लंबाई 300 पिक्स है):
 canvas.drawBitmap(_BMP_line, (_X*60)-240, 0,null); 

वर्ग कार्यान्वयन की शुरुआत में सभी चर जोड़ें।
परिणामस्वरूप, कक्षा इस तरह दिखाई देगी:
 package com.racckat.test_coponent; import java.util.concurrent.TimeUnit; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class CustomButton2 extends View { private Paint mPaint; //   public Bitmap _BMP_line; //   int _Last_Action; //      int _X = 0; //     public Handler myHandler; //      Context _Context; //  public CustomButton(Context context, AttributeSet attrs) { super(context, attrs); _Context = context; //   //   _BMP_line = BitmapFactory.decodeResource(getResources(),R.drawable.line); //   mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(16); mPaint.setColor(0xFFFFFFFF); mPaint.setStyle(Style.FILL); myHandler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what==0){ invalidate(); //    } } }; } @Override public boolean onTouchEvent(MotionEvent event) { //    Float X=(Float)event.getX(); //   X Float Y=(Float)event.getY(); //   Y int Action=event.getAction(); //  if((Action==MotionEvent.ACTION_DOWN)&&(X<60)&&(_Last_Action==0)) { _Last_Action = 1; //  _X = 0; } if((Action==MotionEvent.ACTION_MOVE)&&(_Last_Action == 1)) { _X = (int) (X/60); if (_X>4) _X=4; //     ,    if (_X<0) _X=0; invalidate(); //    } if (Action==MotionEvent.ACTION_UP){ _Last_Action = 2; if (_X>0) MyTimer(); //   else _Last_Action = 0; } return true; } //   public void MyTimer(){ Thread t = new Thread(new Runnable() { public void run() { for(;;){ try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) {e.printStackTrace();} _X--; myHandler.sendEmptyMessage(0); if (_X==0){//      myHandler.sendEmptyMessage(0); //   _Last_Action = 0; //     break; //    } } } }); t.start(); } @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(300, 50); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0,0, 300, 50, mPaint); canvas.drawBitmap(_BMP_line, (_X*60)-240, 0,null); } } 


बाहरी संदेश

हम बहुत स्मार्ट नहीं हैं, हमें इस घटना का एहसास है कि प्रसारण संदेशों की मदद से "टेप छिपा हुआ है"। टाइमर कार्यान्वयन में, संदेश भेजने वाली लाइनें जोड़ें:
  //    Intent intent1 = new Intent("com.anprog.develop.timer_button_alarm"); intent1.putExtra(Name, 1); _Context.sendBroadcast(intent1); //    

चर "नाम" हमारे घटक का नाम संग्रहीत करता है। नाम बचाने के लिए, एक अतिरिक्त प्रक्रिया बनाएं:
 public void SetName(String _name){ Name = _name; } 

घटक नाम जोड़ें - सार्वजनिक स्ट्रिंग नाम ऑब्जेक्ट घोषणा ब्लॉक में।
अब हमारी गतिविधि के निर्माण में, एक प्रसारण अवरोधक जोड़ें:
 //   BroadcastReceiver _br = new BroadcastReceiver() { //     @Override public void onReceive(Context arg0, Intent intent) { int status_alarm_line_button_1 = intent.getIntExtra("line_button_1", 0); if (status_alarm_line_button_1==1) { //     Toast toast = Toast.makeText(getApplicationContext(),"Line alarm!!!", Toast.LENGTH_SHORT); toast.show(); } } }; registerReceiver(_br, new IntentFilter("com.anprog.develop.timer_button_alarm")); 

बटन ऑब्जेक्ट बनाने के लिए लाइन के बाद, ऑब्जेक्ट में नया नाम पास करने के लिए लाइन जोड़ें:
 _CB1.SetName("line_button_1"); //    

सब कुछ, मानक घटक तैयार नहीं है, परीक्षण शुरू करें!
इसे आदर्श रूप से पता लगाना चाहिए - http://youtu.be/3iGxOlWHB0w
आप निम्न लिंक पर सभी टिप्पणियों के साथ नमूना संग्रह डाउनलोड कर सकते हैं - http://www.anprog.com/documents/Line_timer.zip

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


All Articles