English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
اليوم سأقدم لكم كيفية استخدام TextView فقط لإنشاء عدد تنازلي يقلد تطبيقات التجارة الإلكترونية مثل JD.com، Taobao، VIP.com، وما إلى ذلك. في الآونة الأخيرة، لم أستطع أن أجد وقتًا للتعامل معه بسبب العمل المضني في الشركة. اليوم، كان لدي وقت فراغ نادر، وأردت مشاركة هذا معكم، وأتمنى أن نتعلم معًا، وكذلك أن أراجع هذا في المستقبل. لماذا فكرت في استخدام TextView؟ لأن الشركة كانت تقوم ببعض الأعمال التحسينية مؤخرًا، وكان هناك نمط عد تنازلي، حيث استخدم زميلي الذي قام بتطوير هذا العنصر العديد من TextViewات للتجمع معًا، وكان رمزها غير مكتفٍ. لذلك قال مدير المشروع: "شونغ هذا يعود لك لتحسينه، ويتعين أن يكون لديه توسع معين"، وكنت مذهولًا. لم أكن أعرف من أين أبدأ التحسين. ثم نظرت إلى عدة تطبيقات مثل JD.com، Ele.me، VIP.com، وغيرها، وأفتحت واجهة المستخدم للنصوص، ووجدت أن لديهم ميزة مشتركة وهي أنهم يستخدمون View واحدة وليس العديد من TextViewات للتجمع. أعتقد أن الجميع يعرفون أن استخدام TextView فقط هو أفضل من استخدام تجميع العديد من TextViewات. لاختبار هذا، لاختبار هذا.
عند رؤية هذا، فإنه يتبادر إلى ذهن الجميع فكرة إنشاء View مخصصة لتحقيق ذلك. نعم، يمكن تحقيق هذا التأثير باستخدام View مخصصة. ولكن اليوم لن نستخدم View مخصصة. بل سنستخدم TextView.
بسبب أن مدير المشروع طلب من أن يكون رمز هذا التحسين قابلاً للتوسع. لذلك تم تصميم هذا الرمز بإضافة بعض المعرفة الموجهة للأشياء. هناك بعض الأفكار الخاصة في التصميم والهندسة.
أفكار تصميم هذا demo:
1. كتابة كلاس أساسي للعد التنازلي كي يتمكن من تنفيذ وظائف العد التنازلي الأكثر بساطة وأكثر أساسية، وليس لديه أي نمط، دع هذا الكلاس يرث كلاس CountDownTimer، وفي هذا الكلاس
حفظ كائن TextView، وأظهر بيانات العد التنازلي في TextView، ثم قم بإنشاء دالة getmDateTv() لتقديم كائن TextView. ثم يمكنك عرض هذا الكائن في تصميم واجهة المستخدم. هذا بسيط جداً.
2- بعد ذلك، للحصول على العد التنازلي بأسلوب مختلف، يكفي كتابة فئات فرعية مختلفة لتعديل أقل فئة عادية للعد التنازلي، ثم تعديل الطريقتين لتعيين البيانات وتعيين الأسلوب، ثم يمكن إضافة أنواع مختلفة للعد التنازلي العادي. إذا كان هناك حاجة إلى توسيع أنواع العد التنازلي الجديدة، لا تحتاج إلى تعديل كود الفئات الأخرى، فقط كتب فئة عادية للعد التنازلي الفرعية وتعديل الطريقتين، مما يجعل التوسع أكثر مرونة.
3- بعد ذلك، من خلال فئة إدارة TimerUtils، يتم التعامل مع ضغط الفئات الفرعية والفئات الأصلية بشكل مركزي، بحيث يتم توزيع وظائف الفئات الفرعية والأصلية على فئة TimerUtils الإدارية، وتمثل هذه الفئة الإدارية هيئة الاتصال الوحيدة مع العميل، مثل الحصول على كائن العد التنازلي والحصول على TextView العد التنازلي من خلال هذه الفئة الإدارية، مما يمنع العميل من التعامل مباشرة مع الفئة الأساسية للعد التنازلي وفئات الفرعية. وبالتالي، يتم التعبير عن التجميعية والسرية للفئة.
يمكننا الآن النظر في رسم UML البسيط لتصميم هذا Demo:
من خلال هذه الطريقة التحليلية، سنرى الآن ما هي المعارف التي تحتاج إلى استخدامها في تنفيذ هذا Demo.
1- استخدام فئة CountDownTimer.
2- استخدام SpannableString.
3- تعبئة MikyouCountDownTimer.
4- تنفيذ MikyouBackgroundSpan المخصص.
أولاً، من خلال التحليل السابق، يجب أن نعيد مراجعة معرفة CountDownTimer، CountDownTimer هي فئة بسيطة يمكننا رؤية كودها، والاستخدام الطبيعي لها سيكون معروفًا.
CountDownTimer هي فئة抽象ة.
// // مكرر من ملف .class بواسطة IntelliJ IDEA // (مزود بواسطة Fernflower decompiler) // package android.os; public abstract class CountDownTimer { public CountDownTimer(long millisInFuture, long countDownInterval) { throw new RuntimeException("Stub!"); } public final synchronized void cancel() { throw new RuntimeException("Stub!"); } public final synchronized CountDownTimer start() { throw new RuntimeException("Stub!"); } public abstract void onTick(long var1); public abstract void onFinish(); }
يمكن رؤية وقت العد التنازلي الإجمالي هو millisFuture، والخطوة الزمنية الافتراضية للcountDownInterVal هي 1000ms، لذا يتم تعيين البيانات من خلال مكون البناء، ثم يجب تoverwrite回调方法是onTick، والذي يحتوي على معلمة واحدة هي الوقت المتبقي بالمللي ثانية بعد الخطوة الزمنية. ثم كل ما نحتاجه هو إعادة تشكيل الوقت بالمللي ثانية كل 1000ms في دالة onTick للحصول على النمط الزمني للعد التنازلي المطلوب هذا هو تحقيق النمط الأساسي للعد التنازلي. يتم استخدام تنسيق العد التنازلي بتنسيق apache-commons-lang من فئة DurationFormatUtils، حيث يتم تحويل العد التنازلي إلى النمط المطلوب من خلال إدخال تنسيق الوقت.
ثانيًا، استعرض استخدام SpannableString.
في Android، يستخدم EditText للتحرير النص، و TextView لعرض النص، ولكن في بعض الأحيان نحتاج إلى تعيين أنواع النص والتنسيقات الأخرى. يقدم لنا Android فئة SpannableString لتعيين النص المحدد.
1) ForegroundColorSpan لون النص
private void setForegroundColorSpan() {
SpannableString spanString = new SpannableString("لون الأمام");
ForegroundColorSpan span = new ForegroundColorSpan(Color.BLUE);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
2) BackgroundColorSpan لون الخلفية النص
private void setBackgroundColorSpan() {
SpannableString spanString = new SpannableString("لون الخلفية");
BackgroundColorSpan span = new BackgroundColorSpan(Color.YELLOW);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
3) StyleSpan النمط النصي: سميك، مائل إلخ
private void setStyleSpan() { SpannableString spanString = new SpannableString("عريض وسريع"); StyleSpan span = new StyleSpan(Typeface.BOLD_ITALIC); spanString.setSpan(span, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
4) RelativeSizeSpan حجم النسبي
private void setRelativeFontSpan() { SpannableString spanString = new SpannableString("حجم الخط النسبي"); spanString.setSpan(new RelativeSizeSpan(2.5f), 0, 6,Spannable.SPAN_INCLUSIVE_EXCLUSIVE); tv.append(spanString); }
5) TypefaceSpan نوع الخط النصي
private void setTypefaceSpan() { SpannableString spanString = new SpannableString("نوع الخط النصي"); spanString.setSpan(new TypefaceSpan("monospace"), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanText); }
6) URLSpan رابط نصي
private void addUrlSpan() { SpannableString spanString = new SpannableString("رابط"); URLSpan span = new URLSpan("http://www.baidu.com"); spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
7) ImageSpan الصورة
private void addImageSpan() { SpannableString spanString = new SpannableString(" "); drawable d = getResources().getDrawable(R.drawable.ic_launcher); d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE); spanString.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
8) ClickableSpan نص يحتوي على أحداث النقر
private TextView textView; textView = (TextView)this.findViewById(R.id.textView); String text = "Activity عرض"; SpannableString spannableString = new SpannableString(text); spannableString.setSpan(new ClickableSpan() { @Override public void onClick(View widget) { Intent intent = new Intent(Main.this,OtherActivity.class); startActivity(intent); } // يعني أن طول النص الكامل للtext يعمل على تفعيل هذا الحدث }, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(spannableString); textView.setMovementMethod(LinkMovementMethod.getInstance());
9) UnderlineSpan الخطوط
private void addUnderLineSpan() { SpannableString spanString = new SpannableString("الخطوط"); UnderlineSpan span = new UnderlineSpan(); spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
10) StrikethroughSpan
الخط التالي
private void addStrikeSpan() { SpannableString spannableString = new SpannableString("删除线"); StrikethroughSpan span = new StrikethroughSpan(); spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
11) SuggestionSpan
相当于占位符
12) MaskFilterSpan
修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
13) RasterizerSpan
光栅效果
14) AbsoluteSizeSpan
绝对大小(文本字体)
private void setAbsoluteFontSpan() { SpannableString spannableString = new SpannableString("40号字体"); AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(40); spannableString.setSpan(absoluteSizeSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); editText.append(spannableString); }
15) DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
16) TextAppearanceSpan
文本外貌(包括字体、大小、样式和颜色)
private void setTextAppearanceSpan() { SpannableString spanString = new SpannableString("文本外貌"); TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(this, android.R.style.TextAppearance_Medium); spanString.setSpan(textAppearanceSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spanString); }
حسنًا، من خلال هذه النقاط الاستدلالية، يمكننا الآن البدء في تنفيذ demo، ونبدأ معًا في تعبئة العد التنازلي خطوة بخطوة.
أولاً، قم بكتابة كلاس MikyouCountDownTimer الأساسي، واجعله يستمر في كلاس CountDownTimer، وأعلن طرق initSpanData وsetBackgroundSpan لاستخدامها من قبل فروع الأسلوب التنازلي الآخر، يمكنه تحقيق وظيفة العد التنازلي الأساسية.
package com.mikyou.countdowntimer.bean; import android.content.Context; import android.os.CountDownTimer; import android.text.style.ForegroundColorSpan; import android.widget.TextView; import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; import com.mikyou.countdowntimer.utils.TimerUtils; import org.apache.commons.lang.time.DurationFormatUtils; import java.util.ArrayList; import java.util.List; /** * تم إنشائه بواسطة mikyou في 16-10-22. */ public class MikyouCountDownTimer extends CountDownTimer{ private Context mContext;//يُدخل objekt الـ Context protected TextView mDateTv;//TextView واحدة لتحقيق العد التنازلي private long mGapTime;//يُدخل فترات الوقت المحددة للاستخدام كمدة العد التنازلي private long mCount = 1000;//خطوة العد التنازلي، عادة ما تكون 1000 تعني كل ثانية private String mTimePattern = "HH:mm:ss";//يُدخل timePattern نمط الوقت المرسل مثل: HH:mm:ss HH ساعة mm دقيقة ss ثانية dd يوم HH ساعة mm دقيقة ss ثانية private String mTimeStr; protected List<MikyouBackgroundSpan> mBackSpanList; protected List<ForegroundColorSpan> mTextColorSpanList; private int mDrawableId; private boolean flag = false;//ضبط علامة التحقق flag، لتحكم في إعداد Span مرة واحدة protected String[] numbers;//يستخدم هذا النوع من المجموعات لتخزين القيم العددية لليوم، الساعة، الدقيقة، الثانية بعد تفكيك كل حرف من العد التنازلي protected char[] nonNumbers;//تخزين الفترات بين أيام، ساعات، دقائق، ثواني ("يوم","ساعة","دقيقة","ثانية" أو ":") //لإعداد المسافات الداخلية لأسلوب العد التنازلي، حجم الخط، لون الخط، لون فترات العد التنازلي private int mSpanPaddingLeft, mSpanPaddingRight, mSpanPaddingTop, mSpanPaddingBottom; private int mSpanTextSize; private int mSpanTextColor; protected int mGapSpanColor; public MikyouCountDownTimer(Context mContext, long mGapTime, String mTimePattern, int mDrawableId) { this(mContext, mGapTime, 1000, mTimePattern, mDrawableId); } public MikyouCountDownTimer(Context mContext, long mGapTime, int mCount, String mTimePattern, int mDrawableId) { super(mGapTime, mCount); this.mContext = mContext; this.mGapTime = mGapTime; // Total countdown time this.mCount = mCount; // The step length of each countdown, default is 1000 this.mDrawableId = mDrawableId; // Used to set the id of the drawable for the background this.mTimePattern = mTimePattern; // Time format: such as HH:mm:ss or dd days HH hours mm minutes ss seconds, etc. mBackSpanList = new ArrayList<>(); mTextColorSpanList = new ArrayList<>(); mDateTv = new TextView(mContext, null); } // publish these methods to set countdown style, for external calls, so as to customize the countdown style flexibly public MikyouCountDownTimer setTimerTextSize(int textSize) { this.mSpanTextSize = textSize; return this; } public MikyouCountDownTimer setTimerPadding(int left, int top, int right, int bottom) { this.mSpanPaddingLeft = left; this.mSpanPaddingBottom = bottom; this.mSpanPaddingRight = right; this.mSpanPaddingTop = top; return this; } public MikyouCountDownTimer setTimerTextColor(int color){ this.mSpanTextColor = color; return this; } public MikyouCountDownTimer setTimerGapColor(int color){ this.mGapSpanColor = color; return this; } //إعداد نمط Span للعد التنازلي،إعلانها للفرعيات لتنفيذها public void setBackgroundSpan(String timeStr) { إذا (!flag){ initSpanData(timeStr); flag = true; } mDateTv.setText(timeStr); } //إعداد بيانات Span للعد التنازلي،إعلانها للفرعيات لتنفيذها public void initSpanData(String timeStr) { numbers = TimerUtils.getNumInTimerStr(timeStr); nonNumbers = TimerUtils.getNonNumInTimerStr(timeStr); } protected void initBackSpanStyle(MikyouBackgroundSpan mBackSpan) { mBackSpan.setTimerPadding(mSpanPaddingLeft,mSpanPaddingTop,mSpanPaddingRight,mSpanPaddingBottom); mBackSpan.setTimerTextColor(mSpanTextColor); mBackSpan.setTimerTextSize(mSpanTextSize); } @Override public void onTick(long l) { إذا (l > 0) { mTimeStr = DurationFormatUtils.formatDuration(l, mTimePattern); //هذا هو formatDuration في كلاس DurationFormatUtils في مكتبة lang من apache common،من خلال إدخال //يحول وقت معين تلقائيًا إلى نمط mTimePattern المناسب (HH:mm:ss أو dd يوم HH ساعة mm دقيقة ss ثانية) إعداد BackgroundSpan(mTimeStr); } } @Override العمومية void onFinish() { mDateTv.setText("انتهاء العداد التنازلي"); } //لإرجاع كائن TextView الذي يعرض العداد التنازلي العمومية TextView getmDateTv() { startTimer(); إرجاع mDateTv; } العمومية void cancelTimer(){ هذا.cancel(); } العمومية void startTimer(){ هذا.start(); } العمومية String getmTimeStr() { إرجاع mTimeStr; } }
استخدام فئة TimerUtils لتحديد نماذج مختلفة لعداد التنازلي، مثل HH:mm:ss، HH ساعة mm دقيقة ss ثانية، dd يوم HH ساعة mm دقيقة ss ثانية وما إلى ذلك. الآن يمكننا النظر في النمط الأساسي البسيط.
الجزء الثاني: إنشاء MikyouBackgroundSpan لتوليد ImageSpan، هذه الفئة مهمة جدًا وتستخدم لإنشاء نماط TextView لعداد التنازلي، لماذا يمكن استخدام TextView لتحقيق ذلك
لا تنسى أن هناك فئة قوية جدًا هي SpannableString، هذه الفئة تتيح إعداد نمط كل حرف في سلسلة النصوص، هناك العديد من الأنماط. وأخيرًا من خلال استخدام TextView، يمكنك استخدام طريقة setSpan لتحديد
مثل SpannableString لإنشاء إعداد. ولكن لماذا تحتاج إلى Span مخصص؟ لأنه من الغريب لماذا لا يوجد أي Span في android يمكنه إعداد ملف drawable، لذا بحثت كثيرًا على الإنترنت ولم أجد شيئًا، وأخيرًا وجدت حلًا على stackOverFlow من قبل شخص أجنبي، وهو إعادة كتابة ImageSpan حتى يمكن تنفيذ إعداد ملف drawable
باكجيت com.mikyou.countdowntimer.myview; إدراج android.graphics.Canvas; import android.graphics.Color; إدراج android.graphics.Paint; إدراج android.graphics.Rect; إدراج android.graphics.drawable.Drawable; import android.text.style.ImageSpan; /** * تم إنشائه بواسطة mikyou في 16-10-22. */ public class MikyouBackgroundSpan extends ImageSpan { private Rect mTextBound; private int maxHeight = 0; private int maxWidth = 0; private int mPaddingLeft = 20; private int mPaddingRight = 20; private int mPaddingTop = 20; private int mPaddingBottom = 20; private int mTextColor = Color.GREEN; private int mTextSize = 50; public MikyouBackgroundSpan(Drawable d, int verticalAlignment) { super(d, verticalAlignment); mTextBound = new Rect(); } public MikyouBackgroundSpan setTimerTextColor(int mTextColor) { this.mTextColor = mTextColor; return this; } public MikyouBackgroundSpan setTimerTextSize(int textSize){ this.mTextSize = textSize; return this; } public MikyouBackgroundSpan setTimerPadding(int left, int top, int right, int bottom){ this.mPaddingLeft = left; this.mPaddingRight = right; this.mPaddingBottom = bottom; this.mPaddingTop = top; return this; } @Override public void draw(الرسام canvas, النص text, int start, int end, float x, int top, int y, int bottom, Paint paint) { // يتم رسم خلفية محتوى النص paint.setTextSize(mTextSize); // يتم قياس عرض النص وارتفاعه، يتم الحصول على mTextBound paint.getTextBounds(text.toString(), start, end, mTextBound); // يتم تعيين عرض والارتفاع للخلفية النصية، يتم إدخال المعلمات الاربع left, top, right, bottom maxWidth = maxWidth < mTextBound.width() ? mTextBound.width() : maxWidth; maxHeight = maxHeight < mTextBound.height() ? mTextBound.height() : maxHeight; // تم تعيين الأعلى والأكبر من العرض والطول لمنع إعادة الرسم أثناء تغيير الأرقام في العد التنازلي، مما يؤدي إلى ارتجاف عرض والارتفاع الحواف للعد التنازلي // لذا في كل مرة يتم الحصول على الأعلى والأكبر من العرض والطول بدلاً من الحصول على العرض والطول القياسيين كل مرة getDrawable().setBounds(0,0, maxWidth+mPaddingLeft+mPaddingRight,mPaddingTop+mPaddingBottom+maxHeight); //绘制文本背景 super.draw(canvas, text, start, end, x, top, y, bottom, paint); //设置文本的颜色 paint.setColor(mTextColor); //设置字体的大小 paint.setTextSize(mTextSize); int mGapX = (getDrawable().getBounds().width() - maxWidth)/2; int mGapY= (getDrawable().getBounds().height() - maxHeight)/2; //绘制文本内容 canvas.drawText(text.subSequence(start, end).toString(), x + mGapX , y - mGapY + maxHeight/3, paint); }
ثالثًا، تنفيذ العد التنازلي للنمط الأول، والنمط الأول يشير إلى مثل: 12 ساعة 36 دقيقة 27 ثانية أو 12:36:27 وهو فصل القيم والساعات والدقائق والثواني أو ':' ثم تعديل نمط كل جزء من القيم (12 36 27) والفواصل (الساعات الديناميكية الدقائق الثواني أو :) بما في ذلك إضافة خلفية وخطوط للقيم، يحتوي على array number في MikyouCountDownTimer على [12 36 27] و يحتوي array nonumer على [الساعات الديناميكية الدقائق الثواني] أو [ : : ] الفواصل.
package com.mikyou.countdowntimer.bean; import android.content.Context; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; import com.mikyou.countdowntimer.utils.TimerUtils; /** * تم إنشائه بواسطة mikyou في 16-10-22. */ public class JDCountDownTimer extends MikyouCountDownTimer { private SpannableString mSpan; private Context mContext; private int mDrawableId; public JDCountDownTimer(Context mContext, long mGapTime, String mTimePattern,int mDrawableId) { super(mContext, mGapTime, mTimePattern,mDrawableId); this.mContext = mContext; this.mDrawableId = mDrawableId; } /** * يمكن تعريف طريقة initSpanData الخاصة بالآب * يمكن الحصول على كل قطعة من القيم باستخدام مجموعة number للحصول على كل قطعة من Objects من MikyouBackgroundSpan * يمكن تعريف نمط كل قطعة من القيم باستخدام MikyouBackgroundSpan، بما في ذلك الخلفية، والحدود، وطرق الزوايا، وإضافة هذه الأشياء إلى المجموعة * يمكن الحصول على كل فاصل باستخدام مجموعة nonNumber للحصول على كل فاصل من Objects منForegroundColorSpan * يمكن تعريف نمط كل فاصل باستخدام هذه الأشياء، لأنه تم تعريف ForegroundColorSpan فقط، لذا يمكن تعريف * يمكن ضبط لون كل فاصل، ويمكن ضبط النمط الخاص بكل فاصل باستخدام طريقة setmGapSpanColor * يمكن تعريف Span أخرى أيضًا، والإجراء أيضًا بسيط * */ @Override public void initSpanData(String timeStr) { super.initSpanData(timeStr); for (int i = 0; i<numbers.length;i++){ MikyouBackgroundSpan mBackSpan = new MikyouBackgroundSpan(mContext.getDrawable(mDrawableId), ImageSpan.ALIGN_BOTTOM); initBackSpanStyle(mBackSpan); mBackSpanList.add(mBackSpan); } for (int i= 0; i<nonNumbers.length;i++){ ForegroundColorSpan mGapSpan = new ForegroundColorSpan(mGapSpanColor); mTextColorSpanList.add(mGapSpan); } } /** إعادة كتابة طريقة setBackgroundSpan من الصنف الأب * نعرف أن إعداد Span يعتمد بشكل رئيسي على التحكم في المتغيرين start و end * لتحديد نمط النص الفرعي من start إلى end * mGapLen = 1، مما يعني طول قطعة الفجوة * على سبيل المثال: "الساعة"، "الدقيقة"، "الثانية" من "12:36:27"، طول الفجوة بين كل قطعة * لذا، من خلال تدوير مجموعة Span، يمكنك تعيين Span للخط * يمكن أن نرى بسهولة أن Span لكل قطعة من القيم start index:start = i*numbers[i].length() + i*mGapLen; * end = start + numbers[i].length(); * */ @Override public void setBackgroundSpan(String timeStr) { super.setBackgroundSpan(timeStr); int mGapLen = 1; mSpan = new SpannableString(timeStr); for (int i = 0;i<mBackSpanList.size();i++){ int start = i*numbers[i].length() + i*mGapLen; int end = start + numbers[i].length(); TimerUtils.setContentSpan(mSpan,mBackSpanList.get(i),start,end); إذا (i < mTextColorSpanList.size()){//هذا للتأكد من منع نمط 12:36:27 هذا النمط يحتوي على فاصلة واحدة فقط لذا يجب القيام بالتحقق من عدم حدوث إنفصال في البنية TimerUtils.setContentSpan(mSpan, mTextColorSpanList.get(i), end, end + mGapLen); } } mDateTv.setMovementMethod(LinkMovementMethod.getInstance()); // هذا الطريقة مهمة ويجب تفعيلها، وإلا سيكون النمط المرسوم للعد التنازلي مغطىً mDateTv.setText(mSpan); } }
النوع الثاني من التنفيذ العد التنازلي للنوع الثاني يختلف عن النوع الأول في أنه على سبيل المثال: 12:36:27 أو 12 ساعات 36 دقائق 27 ثانية، يتم فصل كل عدد مع الساعات والدقائق والثواني أو ':'، ثم تخصيص نمط كل جزء من الأعداد (1 2 3 6 2 7) وتباعد (الساعات - الدقائق - الثواني أو :)، بما في ذلك إضافة خلفية وحدود للعدادات، حيث يحتوي جدول vipNumber في MikyouCountDownTimer على [1 2 3 6 2 7] وجدول vipnonNumer يحتوي على [الساعات - الدقائق - الثواني] أو [ : :]d للتباعد.
package com.mikyou.countdowntimer.bean; import android.content.Context; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; import com.mikyou.countdowntimer.utils.TimerUtils; import java.util.ArrayList; import java.util.List; /** * تم إنشائه بواسطة mikyou في 16-10-22. */ public class VIPCountDownTimer extends MikyouCountDownTimer { private SpannableString mSpan; private Context mContext; private int mDrawableId; private List<MikyouBackgroundSpan> mSpanList; private String[] vipNumbers; private char[] vipNonNumbers; public VIPCountDownTimer(Context mContext, long mGapTime, String mTimePattern, int mDrawableId) { super(mContext, mGapTime, mTimePattern,mDrawableId); this.mContext = mContext; this.mDrawableId = mDrawableId; mSpanList = new ArrayList<>(); } /** إعادة كتابة طريقة setBackgroundSpan من الصنف الأب * نعرف أن إعداد Span يعتمد بشكل رئيسي على التحكم في المتغيرين start و end * لتحديد النمط للسطر من start إلى end، لتحديد موقع نطاق كل سطر من الأرقام في السطر بأكمله * mGapLen = 1، مما يعني طول قطعة الفجوة * على سبيل المثال: "الساعة"، "الدقيقة"، "الثانية" من "12:36:27"، طول الفجوة بين كل قطعة * لذا، من خلال تدوير مجموعة Span، يمكنك تعيين Span للخط * يمكن أن نرى بسهولة أن Span لكل قطعة من القيم start index:start = i*numbers[i].length() + i*mGapLen; * end = start + numbers[i].length(); * */ @Override public void setBackgroundSpan(String timeStr) { int mGapLen = 1; mSpan = new SpannableString(timeStr); initSpanData(timeStr); int start = 0 ; int count =0; لأنه يجب علينا التحقق من كل قطعة من القيم، لذا يجب علينا التحقق من كل قطعة من القيم للحلقة (int j=start;j<start + vipNumbers[i].toCharArray().length;j++,count++){ TimerUtils.setContentSpan(mSpan,mSpanList.get(count),j,j+mGapLen); } //في هذه اللحظة يعني أننا قد انتهينا من تدوير قيمة معينة، لذا نحتاج إلى تحديث المتغير start بهذه القيمة start = start + vipNumbers[i].toCharArray().length; إذا (i < nonNumbers.length){ TimerUtils.setContentSpan(mSpan,mTextColorSpanList.get(i),start,start+mGapLen); start = start +mGapLen; // إذا كان هناك فاصل، يجب أن يتم إضافة طول كل فاصل وإعادة تعيين متغير start } } mDateTv.setMovementMethod(LinkMovementMethod.getInstance()); mDateTv.setText(mSpan); } /** * يمكن تعريف طريقة initSpanData الخاصة بالآب * يمكن الحصول على كل قطعة من القيم باستخدام مجموعة number للحصول على كل قطعة من Objects من MikyouBackgroundSpan * يمكن تعريف نمط كل قطعة من القيم باستخدام MikyouBackgroundSpan، بما في ذلك الخلفية، والحدود، وطرق الزوايا، وإضافة هذه الأشياء إلى المجموعة * يمكن الحصول على كل فاصل باستخدام مجموعة nonNumber للحصول على كل فاصل من Objects منForegroundColorSpan * يمكن تعريف نمط كل فاصل باستخدام هذه الأشياء، لأنه تم تعريف ForegroundColorSpan فقط، لذا يمكن تعريف * يمكن ضبط لون كل فاصل، ويمكن ضبط النمط الخاص بكل فاصل باستخدام طريقة setmGapSpanColor * يمكن تعريف Span أخرى أيضًا، والإجراء أيضًا بسيط * */ @Override public void initSpanData(String timeStr) { super.initSpanData(timeStr); vipNumbers = TimerUtils.getNumInTimerStr(timeStr); // الحصول على كل رقم، وليس كل قطعة من القيم، وإضافة إلى المجموعة vipNonNumbers = TimerUtils.getNonNumInTimerStr(timeStr); // الحصول على كل فاصل، وإضافة إلى المجموعة لأنه يجب علينا التحقق من كل قطعة من القيم، لذا يجب علينا التحقق من كل قطعة من القيم لأن نحتاج إلى الحصول على كل رقم، لذا يجب علينا التحقق من كل رقم في كل قطعة من القيم، لذا نحتاج إلى دائرة مزدوجة MikyouBackgroundSpan mSpan = new MikyouBackgroundSpan(mContext.getDrawable(mDrawableId), ImageSpan.ALIGN_BOTTOM); initBackSpanStyle(mSpan); mSpanList.add(mSpan); } } for (int i= 0; i<vipNonNumbers.length;i++){ ForegroundColorSpan mGapSpan = new ForegroundColorSpan(mGapSpanColor); mTextColorSpanList.add(mGapSpan); } } }
الجزء الرابع: فئة TimerUtils الإدارية، تقدم كائنات زمنية عكسية بأساليب مختلفة للعميل، لذا فإن هذه الفئة تقوم بإنشاء علاقة مباشرة مع العميل، مما يعكس التجميعية في إخفاء فئات الفرعيات والفئات الأساسية من العالم الخارجي.
package com.mikyou.countdowntimer.utils; import android.content.Context; import android.graphics.Color; import android.text.SpannableString; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import com.mikyou.countdowntimer.bean.JDCountDownTimer; import com.mikyou.countdowntimer.bean.MikyouCountDownTimer; import com.mikyou.countdowntimer.bean.VIPCountDownTimer; /** * تم إنشائه بواسطة mikyou في 16-10-22. */ public class TimerUtils { public static final int JD_STYLE = 0; public static final int VIP_STYLE = 1; public static final int DEFAULT_STYLE = 3; public static final String TIME_STYLE_ONE = "HH:mm:ss"; public static final String TIME_STYLE_TWO = "HH\u65F6mm\u5206ss\u79D2"; public static final String TIME_STYLE_THREE = "dd天HH时mm分ss秒"; public static final String TIME_STYLE_FOUR = "dd天HH时mm分"; public static MikyouCountDownTimer getTimer(int style,Context mContext, long mGapTime, String mTimePattern, int mDrawableId){ MikyouCountDownTimer mCountDownTimer = null; switch (style){ case JD_STYLE: mCountDownTimer = new JDCountDownTimer(mContext, mGapTime, mTimePattern, mDrawableId); break; case VIP_STYLE: mCountDownTimer = new VIPCountDownTimer(mContext, mGapTime, mTimePattern, mDrawableId); break; case DEFAULT_STYLE: mCountDownTimer = new MikyouCountDownTimer(mContext, mGapTime, mTimePattern, mDrawableId); break; } return mCountDownTimer; } //得到倒计时字符串中的数值块部分 public static String[] getNumInTimerStr(String mTimerStr){ return mTimerStr.split("[^\\d]"); } //得到倒计时中字符串中的非数值的字符串,并把数值过滤掉重新组合成一个字符串,并把字符串拆分字符数组,也就是保存倒计时中间的间隔 public static char[] getNonNumInTimerStr(String mTimerStr){ return mTimerStr.replaceAll("\\d", "").toCharArray(); } // تعيين لون النص public static ForegroundColorSpan getTextColorSpan(String color){ ForegroundColorSpan mSpan = null; if (mSpan == null){ mSpan = new ForegroundColorSpan(Color.parseColor(color)); } return mSpan; } // تعيين Span للمحتوى public static void setContentSpan(SpannableString mSpan, Object span, int start, int end) { mSpan.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } }
الآن دعونا نختبر العد التنازلي الذي قمنا بإنشائه باستخدام TextView.
استخدام هذا العد التنازلي بسيط جدًا وسهل، حيث يمكنك تحقيق نمط العد التنازلي لموقع JD وكل المتاجر الإلكترونية بجملة واحدة فقط.
package com.mikyou.countdowntimer; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Gravity; import android.widget.LinearLayout; import android.widget.TextView; import com.mikyou.countdowntimer.utils.TimerUtils; public class MainActivity extends AppCompatActivity { private LinearLayout parent; private int padding =10; private int textSize = 40; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); parent = (LinearLayout) findViewById(R.id.parent); // النمط الافتراضي لحساب العداد يوجد تحت كل نمط زمني أربعة صيغ زمنية /** * الصيغة الزمنية الافتراضية + 1: DEFAULT_STYLE <-> TIME_STYLE_ONE = "HH:mm:ss" * */ TextView tv = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE, this, 120000000, TimerUtils.TIME_STYLE_ONE, 0) .getmDateTv(); parent.addView(tv); setmLayoutParams(tv); /** * الصيغة الزمنية الافتراضية + 2: DEFAULT_STYLE <-> TIME_STYLE_TWO = "HH ساعة mm دقيقة ss ثانية" * */ TextView tv1 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE, this, 120000000, TimerUtils.TIME_STYLE_TWO, 0) .getmDateTv(); parent.addView(tv1); setmLayoutParams(tv1); /** * الصيغة الزمنية الافتراضية + 3: DEFAULT_STYLE <-> TIME_STYLE_THREE = "dd يوم HH ساعة mm دقيقة ss ثانية" * */ TextView tv2 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE, this, 120000000, TimerUtils.TIME_STYLE_THREE, 0) .getmDateTv(); parent.addView(tv2); setmLayoutParams(tv2); /** * الصيغة الزمنية الافتراضية + 4: DEFAULT_STYLE <-> TIME_STYLE_FOUR = "dd يوم HH ساعة mm دقيقة" * */ TextView tv3 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE, this, 120000000, TimerUtils.TIME_STYLE_FOUR, 0) .getmDateTv(); parent.addView(tv3); setmLayoutParams(tv3); // النمط الأول للعد التنازلي، وهو نمط يفصل بين كل قطعة من الأرقام وكل فجوة، وله نمطان مختلفان تحت كل نمط /** * النمط الأول + تنسيق الوقت 1: JD_STYLE <--> TIME_STYLE_ONE = "HH:mm:ss" * */ TextView tv4 = TimerUtils.getTimer(TimerUtils.JD_STYLE, this, 120000000, TimerUtils.TIME_STYLE_ONE, R.drawable.timer_shape) .setTimerPadding(10, 10, 10, 10) // ضبط ال间距 الداخلية .setTimerTextColor(Color.BLACK) // ضبط لون النص .setTimerTextSize(40) // ضبط حجم النص .setTimerGapColor(Color.BLACK) // ضبط لون الفجوة .getmDateTv(); // الحصول على عنصر TextView parent.addView(tv4); setmLayoutParams(tv4); /** * النمط الأول + تنسيق الوقت 2: JD_STYLE <--> TIME_STYLE_TWO = "ساعةHH دقيقةmm ثانيةss" * */ TextView tv5 = TimerUtils.getTimer(TimerUtils.JD_STYLE, this, 120000000, TimerUtils.TIME_STYLE_TWO, R.drawable.timer_shape2) .setTimerPadding(10,10,10,10) .setTimerTextColor(Color.WHITE); .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv5); setmLayoutParams(tv5); /** * النمط الأول + تنسيق الوقت 3: JD_STYLE <--> TIME_STYLE_THREE = "يومdd ساعةHH دقيقةmm ثانيةss" * */ TextView tv6 = TimerUtils.getTimer(TimerUtils.JD_STYLE, this, 120000000, TimerUtils.TIME_STYLE_THREE, R.drawable.timer_shape2) .setTimerPadding(10,10,10,10) .setTimerTextColor(Color.YELLOW) .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv6); setmLayoutParams(tv6); /** * النمط الأول + تنسيق الوقت 4:JD_STYLE <-->TIME_STYLE_FOUR = "dd يوم HH ساعة mm دقيقة" * */ TextView tv7= TimerUtils.getTimer(TimerUtils.JD_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,R.drawable.timer_shape2); .setTimerPadding(15,15,15,15) .setTimerTextColor(Color.BLUE) .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv7); setmLayoutParams(tv7); /** * النمط الثاني + تنسيق الوقت 1:VIP_STYLE <-->TIME_STYLE_ONE = "HH:mm:ss" * */ TextView tv8= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_ONE,R.drawable.timer_shape); .setTimerPadding(15,15,15,15) .setTimerTextColor(Color.BLACK); .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv8); setmLayoutParams(tv8); /** * النمط الثاني + تنسيق الوقت 2:VIP_STYLE <-->TIME_STYLE_TWO = "HH ساعة mm دقيقة ss ثانية" * */ TextView tv9= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_TWO,R.drawable.timer_shape2); .setTimerPadding(15,15,15,15) .setTimerTextColor(Color.WHITE); .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv9); setmLayoutParams(tv9); /** * النمط الثاني + تنسيق الوقت 3:VIP_STYLE <-->TIME_STYLE_THREE = "dd يوم HH ساعة mm دقيقة ss ثانية" * */ TextView tv10= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_THREE,R.drawable.timer_shape2) .setTimerPadding(15,15,15,15) .setTimerTextColor(Color.YELLOW) .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv10); setmLayoutParams(tv10); /** * النمط الثاني + تنسيق الوقت 4:VIP_STYLE <-->TIME_STYLE_FOUR = "dd يوم HH ساعة mm دقيقة" * */ TextView tv11= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,R.drawable.timer_shape2) .setTimerPadding(15,15,15,15) .setTimerTextColor(Color.BLUE) .setTimerTextSize(40) .setTimerGapColor(Color.BLACK) .getmDateTv(); parent.addView(tv11); setmLayoutParams(tv11); } private void setmLayoutParams(TextView tv) { tv.setGravity(Gravity.CENTER_HORIZONTAL); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tv.getLayoutParams(); params.setMargins(20,20,20,20); tv.setLayoutParams(params); } }
ملفان drawable اثنين:
نمط مع الهوامش
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> android:shape="rectangle" > <corners android:radius="5px"/> <stroke android:color="#88000000" android:width="1dp"/> </shape>
نمط مع الخلفية والهوامش
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> android:shape="rectangle" > <corners android:radius="10px"/> <solid android:color="#000000"/> </shape>
لنرى الآن النتيجة التي نحصل عليها.
أنظروا إلى النتيجة النهائية، في الواقع يمكن تعريف أنماط متعددة، يعتمد ذلك على الإبداع والفكرة الخاصة بك، إذا كان هناك أي نقاط ضعف في هذا التعقيد للعد التنازلي، فالرجاء تقديم الكثير من النصائح. ولكن الآن، استخدامه سهل وسهل، يمكن حل المشكلة في سطر واحد. يستخدم هذا العد التنازلي في العديد من الأماكن، إذا كنت بحاجة إليه، يمكنك إضافته مباشرة إلى مشروعك الخاص.
ما ذكرته أعلاه هو ما قدمه المحرر لكم حول كيفية استخدام TextView لتحقيق تأثير العد التنازلي المقلد لـ JD وTaobao في Android، آمل أن يكون مفيدًا لكم، إذا كان لديكم أي أسئلة، فالرجاء ترك تعليق، وسأقوم بالرد على أسئلتكم في أقرب وقت ممكن، وأنا أيضًا أتمنى أن تكونوا قد دعمتم موقع呐喊 التعليمي!
بيان: محتوى هذا المقال تم جمعه من الإنترنت، حقوق النشر تخص المالك الأصلي، المحتوى تم إضافته من قبل مستخدمي الإنترنت بتحميلهم بشكل مستقل، هذا الموقع لا يمتلك حقوق الملكية، لم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل أي مسؤولية قانونية. إذا كنت قد وجدت محتوى يشتبه في انتهاك حقوق النسخ، فالرجاء إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # ب @) لإبلاغنا، وقدم الدليل على الدليل، إذا تم التحقق من صحة الشكوى، سيتم حذف المحتوى المزعوم فوراً.