English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
في المشروع، تحتاج إلى وظيفة تحديث السحب، ولكن هذا العنصر ليس من النوع ListView وغيرها من التحكمات، بل يجب أن يتمكن ViewGroup من تنفيذ هذه الوظيفة، في البداية بحثت قليلاً على الإنترنت، لم أجد ما يتناسب مع ما أبحث عنه، ولم أفهم الشيفرة أيضًا، لذا قررت أن أكتبها بنفسي
لذا أخرجت شيفرة XlistView وأخذت أقرأها خطوة بخطوة، وبعد فهم شيفرة XLisview بشكل عام، قررت أن أقوم بذلك بنفسي
للراحة، استخدمت headView من XListView HeadView، مما ساعدني على توفير الكثير من الوقت:)
تحديث السحب أسفل، تحديث السحب أسفل، يجب أولاً تنفيذ وظيفة السحب، في البداية كنت أفكر في استخدام extends ScrollView لأن هناك تأثيرات تمرير مدمجة، ولكن بعد ذلك تخليت عن هذا بسبب سببين:
1、يمكن وضع فقط عنصر واجهة مستخدم واحد تحت ScrollView، على الرغم من أنني أضفت ViewGroup تحت Scroll، ثم أضفت headView بشكل ديناميكي إلى ViewGroup الأم، ولكنني كنت متعودًا على عرض الاستوديو المرئي، حيث يبدو غير واضح!
2、 عند دمج ListView داخل ScrollView يحدث 冲突، لذا يجب إعادة كتابة ListView. لذا تخليت عن هذه الفكرة واتخذت思路 مختلفة!
بشأن السبب السابق 1: يمكن إضافة headView إلى GroupView داخل ScrollView بشكل ديناميكي، عن طريق إعادة كتابة طريقة onViewAdded() الخاصة بScrollView، وإضافة headView المفجر في هذه المرحلة
@Override public void onViewAdded(View child) { super.onViewAdded(child); // لأن headView يجب أن يكون في الأعلى، أول ما فكرت فيه هو LinearLayout Vertical LinearLayout linearLayout = (LinearLayout) getChildAt(0); linearLayout.addView(view, 0); }
دعنا نغير الطريقة، من خلال استخدام extends LinearLayout!
دعنا نقوم بتحضير العمل، نحتاج إلى HeaderView والحصول على ارتفاع HeaderView وارتفاع Layout في البداية
private void initView(Context context) { mHeaderView = new SRefreshHeader(context); mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.slistview_header_content); setOrientation(VERTICAL); addView(mHeaderView, 0); getHeaderViewHeight(); getViewHeight(); }
mHeaderView = new SRefreshHeader(context);
تم استنساخ HeaderView من خلال طريقة البناء
mHeaderViewContent = (RelativeLayout);
mHeaderView.findViewById(R.id.slistview_header_content);
هذا هو تحليل منطقة المحتوى لHeaderView، سأحصل على ارتفاع هذا العنصر لاحقًا، ستعلمون لماذا لا أستخدم mHeaderView لتحديد الارتفاع، يمكنك النظر في الكود التالي في طريقة بناء المكون
// 初始情况,设置下拉刷新view高度为0 LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.listview_head_view_layout, null); w(mContainer, lp);
إذا قمت بتحديد ارتفاع mHeaderView مباشرة، فإنه سيكون بالتأكيد 0
getHeaderViewHeight();
getViewHeight();
وهي الحصول على ارتفاع HeaderView وارتفاع Layout الأصلي
/** * الحصول على ارتفاع headView */ private void getHeaderViewHeight() { ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } /** * الحصول على ارتفاع نموذج SRefreshLayout الحالي */ private void getViewHeight() { ViewTreeObserver thisView = getViewTreeObserver(); thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); }
إتمام التحضير، والآن ننتقل إلى عملية السحب
إلى هنا، من المؤكد أنك فكرت في طريقة onTouchEvent()، نعم! الآن سنبدأ في العمل هنا
لتحقيق السحب، سيتم تجربة ثلاث مراحل
ACTION_UP→ACTION_MOVE→ACTION_UP
في حدث ACTION_UP، وهو وقت ضغط الأصبع، كل ما يجب القيام به هو تسجيل مكان الضغط عند ذلك الوقت
switch (ev.getAction()) { حالة MotionEvent.ACTION_DOWN: //تسجيل الارتفاع البدءي mLastY = ev.getRawY();//تسجيل الإحداثيات Y عند الضغط break;
ثم يأتي حدث ACTION_MOVE، وهو أكثر أهمية، لأن تغيير ارتفاع HeadView وLayout يتم هنا
حالة MotionEvent.ACTION_MOVE: if (!isRefreashing) isRefreashing = true; final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); updateHeaderViewHeight(deltaY / 1.8f);//تناسب مسافة التحرك بنسبة معينة updateHeight(); break;
في الداخل، updateHeaderViewHeight وupdateHeight هي لتغيير ارتفاع HeaderView وارتفاع Layout
private void updateHeight() { ViewGroup.LayoutParams lp = getLayoutParams(); //更新当前layout实例高度为headerView高度加上最初的layout高度 //如果不更新layout 会造成内容高度压缩 无法保持比例 lp.height = (mHeight + mHeaderView.getVisiableHeight()); setLayoutParams(lp); } private void updateHeaderViewHeight(float space) { // if (space < 0) // space = 0; // int factHeight = (int) (space - mHeaderViewHeight); if (mHeaderView.getStatus() != SRefreshHeader.STATE_REFRESHING) { //如果不处于刷新中同时如果高度 if (mHeaderView.getVisiableHeight() < mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_NORMAL) { mHeaderView.setState(SRefreshHeader.STATE_NORMAL); } if (mHeaderView.getVisiableHeight() > mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_READY); } } mHeaderView.setVisiableHeight((int) space + mHeaderView.getVisiableHeight()); }
عند تحديث ارتفاع Header، يتم استخدام المسافة المنزلقة للتحقق من الوصول إلى مسافة التحديث، في الكود أعلاه لقد قمت بتعيين الوصول إلى ضعف ارتفاعHeaderView الأصلي، ينتقل إلى حالة "إطلاق التحديث"، وإذا لم يصل إلى ذلك يتم الحفاظ على حالة "سحب التحديث"
تم تعيين حالةHeaderView في HeaderView إلى 3 حالات هي
public final static int STATE_NORMAL = 0;//下拉刷新 public final static int STATE_READY = 1;//释放刷新 public final static int STATE_REFRESHING = 2;//刷新中
طريقة تحديث الارتفاع هي نفسها لHeaderView وlayout، وهي إضافة المسافة المتنقلة إلى الارتفاع الأصلي وإعادة تعيينها لHeaderView أو layout
mHeaderView.setVisiableHeight((int) space
+ mHeaderView.getVisiableHeight());
آخر شيء هو حدث ACTION_UP وهو وقت خروج الأصبع من الشاشة، هنا نحتاج إلى اتخاذ قرار حول حالةHeaderView الحالية لتحديد حالةHeaderView النهائية!
حالة MotionEvent.ACTION_UP: //عند الإفراج //حماية من تفاعل النقر if (!isRefreashing) break; //إذا كانت حالة headView في حالة READY فهذا يعني أنه يجب الذهاب إلى حالة REFRESHING عند الإفراج if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); } //إعادة تعيين ارتفاع headView حسب حالة SrefreshLayout الحالية وارتفاع headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1;//إعادة تعيين الإحداثيات break;
resetHeadView and reset are methods to reset the headerView height and layout height respectively
private void reset(int status) { ViewGroup.LayoutParams lp = getLayoutParams(); switch (status) { حالة SRefreshHeader.STATE_REFRESHING: lp.height = mHeight + mHeaderViewHeight; break; case SRefreshHeader.STATE_NORMAL: lp.height = mHeight; break; } setLayoutParams(lp); } private void resetHeadView(int status) { switch (status) { حالة SRefreshHeader.STATE_REFRESHING: mHeaderView.setVisiableHeight(mHeaderViewHeight); break; case SRefreshHeader.STATE_NORMAL: mHeaderView.setVisiableHeight(0); break; } }
the implementation method is the same. According to the status, if it is in the refreshing state, the headerView should be displayed normally and the height should be the initial height. If it is in NORMAL, that is, the "pull-to-refresh" state, then the refresh has not been triggered, when resetting, the headerView should be hidden, that is, the height is reset to 0
here the pull-to-refresh operation is also basically completed, and it is necessary to add a callback interface for notification
interface OnRefreshListener { void onRefresh(); }
حالة MotionEvent.ACTION_UP: //عند الإفراج //حماية من تفاعل النقر if (!isRefreashing) break; //إذا كانت حالة headView في حالة READY فهذا يعني أنه يجب الذهاب إلى حالة REFRESHING عند الإفراج if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); if (mOnRefreshListener != null) mOnRefreshListener.onRefresh(); } //إعادة تعيين ارتفاع headView حسب حالة SrefreshLayout الحالية وارتفاع headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1;//إعادة تعيين الإحداثيات break;
Well, it's basically done here, try the effect. Oh, found a problem, why can't this Layout perform pull-to-refresh when nested ListView? Think carefully, it should be a problem with event distribution, and the event intercept needs to be handled!
about the event intercept handling, read the blog of Hongyang Master about.ViewGroup event distribution and part of the source code of Android-Ultra-Pull-To-Refresh, and found the solution from it:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { AbsListView absListView = null; for (int n = 0; n < getChildCount(); n++) { if (getChildAt(n) instanceof AbsListView) { absListView = (ListView) getChildAt(n); Logs.v("إيجاد listView"); } } if (absListView == null) return super.onInterceptTouchEvent(ev); switch (ev.getAction()) { حالة MotionEvent.ACTION_DOWN: mStartY = ev.getRawY(); break; حالة MotionEvent.ACTION_MOVE: float space = ev.getRawY() - mStartY; Logs.v("space:" + space); if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { Logs.v("منع ناجح"); return true; } else { Logs.v("لا يمنع"); return false; } } return super.onInterceptTouchEvent(ev); }
where
if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0)
space means the distance of movement, canScrollVertically() is used to determine whether ListView can scroll vertically, with a negative parameter indicating upward and a positive parameter indicating downward scrolling, the last one is the position of the first visible item in ListView
adding the event intercept handling, a ViewGroup that meets the requirements mentioned at the beginning is also completed!
below is the source code of Layout and HeaderView (the HeaderView used directly is XlistView's HeaderView)
public class SRefreshLayout extends LinearLayout { private SRefreshHeader mHeaderView; private RelativeLayout mHeaderViewContent; private boolean isRefreashing; private float mLastY = -1;//按下的起始高度 private int mHeaderViewHeight;//headerView内容高度 private int mHeight;//طول التخطيط private float mStartY; interface OnRefreshListener { void onRefresh(); } public OnRefreshListener mOnRefreshListener; public SRefreshLayout(Context context) { super(context); initView(context); } public SRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public SRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { mHeaderView = new SRefreshHeader(context); mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.slistview_header_content); setOrientation(VERTICAL); addView(mHeaderView, 0); getHeaderViewHeight(); getViewHeight(); } /** * الحصول على ارتفاع headView */ private void getHeaderViewHeight() { ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } /** * الحصول على ارتفاع نموذج SRefreshLayout الحالي */ private void getViewHeight() { ViewTreeObserver thisView = getViewTreeObserver(); thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { AbsListView absListView = null; for (int n = 0; n < getChildCount(); n++) { if (getChildAt(n) instanceof AbsListView) { absListView = (ListView) getChildAt(n); Logs.v("إيجاد listView"); } } if (absListView == null) return super.onInterceptTouchEvent(ev); switch (ev.getAction()) { حالة MotionEvent.ACTION_DOWN: mStartY = ev.getRawY(); break; حالة MotionEvent.ACTION_MOVE: float space = ev.getRawY() - mStartY; Logs.v("space:" + space); if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { Logs.v("منع ناجح"); return true; } else { Logs.v("لا يمنع"); return false; } } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) mLastY = ev.getRawY(); switch (ev.getAction()) { حالة MotionEvent.ACTION_DOWN: //تسجيل الارتفاع البدءي mLastY = ev.getRawY();//تسجيل الإحداثيات Y عند الضغط break; //عندما يترك الإصبع الشاشة حالة MotionEvent.ACTION_UP: //عند الإفراج //حماية من تفاعل النقر if (!isRefreashing) break; //إذا كانت حالة headView في حالة READY فهذا يعني أنه يجب الذهاب إلى حالة REFRESHING عند الإفراج if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); if (mOnRefreshListener != null) mOnRefreshListener.onRefresh(); } //إعادة تعيين ارتفاع headView حسب حالة SrefreshLayout الحالية وارتفاع headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1;//إعادة تعيين الإحداثيات break; حالة MotionEvent.ACTION_MOVE: if (!isRefreashing) isRefreashing = true; final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); updateHeaderViewHeight(deltaY / 1.8f);//تناسب مسافة التحرك بنسبة معينة updateHeight(); break; } return super.onTouchEvent(ev); } private void reset(int status) { ViewGroup.LayoutParams lp = getLayoutParams(); switch (status) { حالة SRefreshHeader.STATE_REFRESHING: lp.height = mHeight + mHeaderViewHeight; break; case SRefreshHeader.STATE_NORMAL: lp.height = mHeight; break; } setLayoutParams(lp); } private void resetHeadView(int status) { switch (status) { حالة SRefreshHeader.STATE_REFRESHING: mHeaderView.setVisiableHeight(mHeaderViewHeight); break; case SRefreshHeader.STATE_NORMAL: mHeaderView.setVisiableHeight(0); break; } } private void updateHeight() { ViewGroup.LayoutParams lp = getLayoutParams(); //更新当前layout实例高度为headerView高度加上最初的layout高度 //如果不更新layout 会造成内容高度压缩 无法保持比例 lp.height = (mHeight + mHeaderView.getVisiableHeight()); setLayoutParams(lp); } private void updateHeaderViewHeight(float space) { // if (space < 0) // space = 0; // int factHeight = (int) (space - mHeaderViewHeight); if (mHeaderView.getStatus() != SRefreshHeader.STATE_REFRESHING) { //如果不处于刷新中同时如果高度 if (mHeaderView.getVisiableHeight() < mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_NORMAL) { mHeaderView.setState(SRefreshHeader.STATE_NORMAL); } if (mHeaderView.getVisiableHeight() > mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_READY); } } mHeaderView.setVisiableHeight((int) space + mHeaderView.getVisiableHeight()); } public void stopRefresh() { if (mHeaderView.getStatus() == SRefreshHeader.STATE_REFRESHING) { mHeaderView.setState(SRefreshHeader.STATE_NORMAL); resetHeadView(SRefreshHeader.STATE_NORMAL); reset(SRefreshHeader.STATE_NORMAL); } } public void setOnRefreshListener(OnRefreshListener onRefreshListener) { this.mOnRefreshListener = onRefreshListener; } }
public class SRefreshHeader extends LinearLayout { private LinearLayout mContainer; private int mState = STATE_NORMAL; private Animation mRotateUpAnim; private Animation mRotateDownAnim; private final int ROTATE_ANIM_DURATION = 500; public final static int STATE_NORMAL = 0;//下拉刷新 public final static int STATE_READY = 1;//释放刷新 public final static int STATE_REFRESHING = 2;//刷新中 private ImageView mHeadArrowImage; private TextView mHeadLastRefreashTimeTxt; private TextView mHeadHintTxt; private TextView mHeadLastRefreashTxt; private ProgressBar mRefreshingProgress; public SRefreshHeader(Context context) { super(context); initView(context); } /** * @param context * @param attrs */ public SRefreshHeader(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) { // 初始情况,设置下拉刷新view高度为0 LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.listview_head_view_layout, null); addView(mContainer, lp); setGravity(Gravity.BOTTOM); mHeadArrowImage = (ImageView) findViewById(R.id.slistview_header_arrow); mHeadLastRefreashTimeTxt = (TextView) findViewById(R.id.slistview_header_time); mHeadHintTxt = (TextView) findViewById(R.id.slistview_header_hint_text); mHeadLastRefreashTxt = (TextView) findViewById(R.id.slistview_header_last_refreash_txt); mRefreshingProgress = (ProgressBar) findViewById(R.id.slistview_header_progressbar); mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION); mRotateUpAnim.setFillAfter(true); mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION); mRotateDownAnim.setFillAfter(true); } public void setState(int state) { if (state == mState) return; if (state == STATE_REFRESHING) { // عرض التقدم mHeadArrowImage.clearAnimation(); mHeadArrowImage.setVisibility(View.INVISIBLE); mRefreshingProgress.setVisibility(View.VISIBLE); } else { // عرض صورة السهم mHeadArrowImage.setVisibility(View.VISIBLE); mRefreshingProgress.setVisibility(View.INVISIBLE); } switch (state) { case STATE_NORMAL: if (mState == STATE_READY) { mHeadArrowImage.startAnimation(mRotateDownAnim); } if (mState == STATE_REFRESHING) { mHeadArrowImage.clearAnimation(); } mHeadHintTxt.setText("أزح下拉以刷新"); break; case STATE_READY: if (mState != STATE_READY) { mHeadArrowImage.clearAnimation(); mHeadArrowImage.startAnimation(mRotateUpAnim); mHeadHintTxt.setText("أطلق لإعادة التحديث"); } break; case STATE_REFRESHING: mHeadHintTxt.setText("جاري التحديث"); break; default: } mState = state; } public void setVisiableHeight(int height) { if (height < 0) height = 0; LayoutParams lp = (LayoutParams) mContainer .getLayoutParams(); lp.height = height; mContainer.setLayoutParams(lp); } public int getStatus() { return mState; } public int getVisiableHeight() { return mContainer.getHeight(); } }
آخر هو ملف التخطيط
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="bottom"> <RelativeLayout android:id="@+id/slistview_header_content" android:layout_width="match_parent" android:layout_height="60dp"> <LinearLayout android:id="@+id/slistview_header_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/slistview_header_hint_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉刷新" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp"> <TextView android:id="@+id/slistview_header_last_refreash_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="上次刷新时间" android:textSize="12sp" /> <TextView android:id="@+id/slistview_header_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" /> </LinearLayout> </LinearLayout> <ProgressBar android:id="@+id/slistview_header_progressbar" android:layout_width="30dp" android:layout_height="30dp" android:layout_centerVertical="true" android:layout_toLeftOf="@id/slistview_header_text" android:visibility="invisible" /> <ImageView android:id="@+id/slistview_header_arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/slistview_header_progressbar" android:layout_centerVertical="true" android:layout_toLeftOf="@id/slistview_header_text" android:src="@drawable/mmtlistview_arrow" /> </RelativeLayout> </LinearLayout>
هذا هو نهاية محتوى هذا المقال، نأمل أن يكون قد ساعدكم في التعلم، ونأمل أن تدعموا تعليمات呐喊 بشكل أكبر.
البيان: محتويات هذا المقال تم جمعها من الإنترنت، وتعود حقوق الملكية للمالك الأصلي، تم إضافة المحتوى من قبل مستخدمي الإنترنت بطرقهم الخاصة، ويتمتع هذا الموقع بلا حقوق ملكية، لم يتم تعديل المحتوى بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية متعلقة بذلك. إذا اكتشفت محتوى يشتبه في انتهاك حقوق النسخ، فلا تتردد في إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # ب @) لتقديم الشكوى، وقدم الدليل على ذلك، وسيتم حذف المحتوى المزعوم عن الفساد على الفور إذا تم التحقق منه.