English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Nel progetto è necessario implementare la funzione di aggiornamento con scorrimento verso il basso, ma questo View non è un controllo di tipo ListView, è necessario implementare la funzione tramite ViewGroup, all'inizio ho cercato un po' su internet, ma non ho trovato nulla particolarmente adatto, il codice non è stato né facile da capire, quindi ho deciso di scriverlo da solo.
Così, ho estratto il codice sorgente di XlistView e l'ho letto un pezzo alla volta, dopo aver compreso approssimativamente il codice sorgente di XLisview, ho deciso di fare io stesso!
Per semplificare, headView ha ancora usato HeadView di XListView, risparmiando molto lavoro:(
Aggiornamento con scorrimento verso il basso, aggiornamento con scorrimento verso il basso, ovviamente, è necessario implementare prima la funzione di scorrimento verso il basso, all'inizio avevo intenzione di implementarlo tramite extends ScrollView, perché ci sono già effetti di scorrimento pronti, ma ho abbandonato per due motivi:
1、Sotto un ScrollView può esserci solo un controllo View; anche se si aggiunge un ViewGroup sotto Scroll, e si aggiunge headView dinamicamente al ViewGroup iniziale, preferisco la visualizzazione visiva di studio, che sembra meno intuitiva!
2、Quando un ScrollView contiene un ListView, si verifica una collisione; è necessario anche sovrascrivere ListView. Così, ho abbandonato e cambiato idea!
Riguardo alla ragione sopra menzionata 1: per aggiungere dinamicamente headView nel GroupView di ScrollView, è possibile sovrascrivere il metodo onViewAdded() di ScrollView e aggiungere headView al GroupView figlio inizializzato
@Override public void onViewAdded(View child) { super.onViewAdded(child); //Perché headView deve essere sopra tutti, la prima idea è quella di usare un LinearLayout Verticale LinearLayout linearLayout = (LinearLayout) getChildAt(0); linearLayout.addView(view, 0); }
Cambiando prospettiva, proviamo a implementarlo tramite extends LinearLayout!
Facciamo prima le preparazioni, ci serve un HeaderView e dobbiamo ottenere l'altezza di HeaderView e l'altezza iniziale di 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);
Eseguire l'istanziazione di HeaderView tramite il costruttore
mHeaderViewContent = (RelativeLayout)
mHeaderView.findViewById(R.id.slistview_header_content);
Questo è il contenuto dell'area di headerView, tra poco lo utilizzeremo per ottenere l'altezza, probabilmente vi chiederete perché non utilizzare mHeaderView per ottenere l'altezza, entrando nel metodo costruttore, vedete il seguente codice
// 初始情况,设置下拉刷新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);
Se si ottiene direttamente l'altezza di mHeaderView, sicuramente sarà 0
getHeaderViewHeight();
getViewHeight();
Rispettivamente, ottenere l'altezza di HeaderView e l'altezza iniziale di Layout
/** * Ottenere l'altezza di headView */ private void getHeaderViewHeight() { ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } /** * Ottenere l'altezza dell'istanza corrente di SRefreshLayout */ private void ottieniAltezza() { ViewTreeObserver thisView = getViewTreeObserver(); thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); }
Le preparazioni sono completate, quindi ora dobbiamo eseguire l'operazione di scorrimento a discesa
Arrivati a questo punto, probabilmente penserete subito al metodo onTouchEvent(), sì! Ora iniziamo a lavorare qui
Per realizzare lo scorrimento a discesa, ci sono in totale tre fasi
ACTION_UP→ACTION_MOVE→ACTION_UP
Nell'evento ACTION_UP, ovvero quando il dito viene premuto, tutto ciò che dobbiamo fare è registrare le coordinate di quando viene premuto
switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // Registrare l'altezza iniziale mLastY = ev.getRawY(); // Registrare la Y coordinate quando si preme break;
Poi c'è l'evento ACTION_MOVE, che è molto importante, perché la variazione dell'altezza di HeadView e Layout durante lo scorrimento si verifica qui
case MotionEvent.ACTION_MOVE: if (!isRefreashing) isRefreashing = true; final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); updateHeaderViewHeight(deltaY / 1.8f); // Per una certa proporzioni ridurre la distanza di movimento updateHeight(); break;
All'interno, updateHeaderViewHeight e updateHeight sono rispettivamente per modificare l'altezza di HeaderView e Layout
private void updateHeight() { ViewGroup.LayoutParams lp = getLayoutParams(); // Aggiorna l'altezza dell'istanza corrente del layout all'altezza del headerView più l'altezza iniziale del layout // Se non si aggiorna il layout, la altezza del contenuto verrà compressa, non potendo mantenere la proporzioni 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) { // Se non si trova in uno stato di aggiornamento e se l'altezza 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()); }
Quando si aggiorna l'altezza del Header, si giudica se si è raggiunto la distanza di aggiornamento tramite lo spostamento di scorrimento, nel codice sopra definito, è impostato come due volte l'altezza iniziale di mHeaderView, quindi entra nello stato di 'Rilascia per aggiornare', se non raggiunge, mantiene lo stato di 'Tira per aggiornare'
Lo stato di HeaderView è impostato in tre, rispettivamente
public final static int STATE_NORMAL = 0;//正常状态 public final static int STATE_READY = 1;//准备刷新 public final static int STATE_REFRESHING = 2;//正在刷新
Il metodo per aggiornare l'altezza è lo stesso per headerView e layout, ovvero aggiungere la distanza di spostamento all'altezza originale e assegnarla di nuovo a headerView o layout
mHeaderView.setVisiableHeight((int) space
+ mHeaderView.getVisiableHeight());
Infine, c'è l'evento ACTION_UP, che si verifica quando il dito lascia lo schermo. In questo caso, dobbiamo determinare lo stato finale di headerView in base allo stato attuale di headerView!
case MotionEvent.ACTION_UP: // Al rilascio // Evitare che vengano attivati gli eventi di click if (!isRefreashing) break; // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); } // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1; // Riportare le coordinate a zero break;
resetHeadView e reset sono i metodi per reimpostare l'altezza del headerView e dell'layout
private void reset(int status) { ViewGroup.LayoutParams lp = getLayoutParams(); switch (status) { case 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) { case SRefreshHeader.STATE_REFRESHING: mHeaderView.setVisiableHeight(mHeaderViewHeight); break; case SRefreshHeader.STATE_NORMAL: mHeaderView.setVisiableHeight(0); break; } }
Il modo di implementazione è lo stesso. Secondo lo stato, se è in fase di refresh, il headerView dovrebbe essere visualizzato normalmente e l'altezza dovrebbe essere quella iniziale, se è in stato NORMAL, ossia lo stato di 'refresh a scorrimento', allora non è stato attivato il refresh, durante il reset, il headerView dovrebbe essere nascosto, ossia l'altezza dovrebbe essere reimpostata a 0
Arrivati a questo punto, l'operazione di refresh a scorrimento è quasi completata, ma è necessario aggiungere un'interfaccia di callback per la notifica
interface OnRefreshListener { void onRefresh(); }
case MotionEvent.ACTION_UP: // Al rilascio // Evitare che vengano attivati gli eventi di click if (!isRefreashing) break; // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); if (mOnRefreshListener != null) mOnRefreshListener.onRefresh(); } // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1; // Riportare le coordinate a zero break;
Bene, qui è quasi completato, proviamo l'effetto. Oh, ho trovato un problema, perché questo Layout non può eseguire il refresh a scorrimento quando è contenuto in una ListView. riflettendoci, sembra essere un problema di distribuzione degli eventi, che deve essere gestito!
Per la gestione dell'intercettazione degli eventi, ho letto il blog di viewgroup event dispatch di Hongyang e una parte del codice sorgente di Android-Ultra-Pull-To-Refresh, da cui ho trovato la soluzione:
@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()) { case MotionEvent.ACTION_DOWN: mStartY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: float space = ev.getRawY() - mStartY; Logs.v("space:\ if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { Logs.v("拦截成功"); return true; } else { Logs.v("非拦截"); return false; } } return super.onInterceptTouchEvent(ev); }
tra cui
if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0)
space è la distanza spostata, canScrollVertically() è usato per determinare se la ListView può scorrere verticalmente, con un parametro negativo rappresenta lo spostamento verso l'alto, un parametro positivo rappresenta lo spostamento verso il basso, e l'ultimo è la posizione dell'elemento visibile della ListView
Aggiungendo la gestione dell'intercettazione degli eventi, il ViewGroup che soddisfa le esigenze menzionate all'inizio è completato!
Di seguito, il codice sorgente del Layout e del HeaderView (usato direttamente il HeaderView di XlistView)
public class SRefreshLayout extends LinearLayout { private SRefreshHeader mHeaderView; private RelativeLayout mHeaderViewContent; private boolean isRefreashing; private float mLastY = -1; // altezza iniziale della pressione private int mHeaderViewHeight; // altezza del contenuto headerView private int mHeight;// altezza del layout 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(); } /** * Ottenere l'altezza di headView */ private void getHeaderViewHeight() { ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } /** * Ottenere l'altezza dell'istanza corrente di SRefreshLayout */ private void ottieniAltezza() { 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()) { case MotionEvent.ACTION_DOWN: mStartY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: float space = ev.getRawY() - mStartY; Logs.v("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()) { case MotionEvent.ACTION_DOWN: // Registrare l'altezza iniziale mLastY = ev.getRawY(); // Registrare la Y coordinate quando si preme break; // Quando il dito lascia lo schermo case MotionEvent.ACTION_UP: // Al rilascio // Evitare che vengano attivati gli eventi di click if (!isRefreashing) break; // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); if (mOnRefreshListener != null) mOnRefreshListener.onRefresh(); } // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView resetHeadView(mHeaderView.getStatus()); reset(mHeaderView.getStatus()); mLastY = -1; // Riportare le coordinate a zero break; case MotionEvent.ACTION_MOVE: if (!isRefreashing) isRefreashing = true; final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); updateHeaderViewHeight(deltaY / 1.8f); // Per una certa proporzioni ridurre la distanza di movimento updateHeight(); break; } return super.onTouchEvent(ev); } private void reset(int status) { ViewGroup.LayoutParams lp = getLayoutParams(); switch (status) { case 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) { case SRefreshHeader.STATE_REFRESHING: mHeaderView.setVisiableHeight(mHeaderViewHeight); break; case SRefreshHeader.STATE_NORMAL: mHeaderView.setVisiableHeight(0); break; } } private void updateHeight() { ViewGroup.LayoutParams lp = getLayoutParams(); // Aggiorna l'altezza dell'istanza corrente del layout all'altezza del headerView più l'altezza iniziale del layout // Se non si aggiorna il layout, la altezza del contenuto verrà compressa, non potendo mantenere la proporzioni 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) { // Se non si trova in uno stato di aggiornamento e se l'altezza 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>
Questo è tutto il contenuto dell'articolo, speriamo che sia utile per la tua apprendimento e che tu supporti fortemente la guida di urla.
Dichiarazione: il contenuto di questo articolo è stato prelevato da Internet, il copyright spetta agli autori, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una email a notice#oldtoolbag.com (sostituisci # con @) per segnalare il problema, fornendo prove pertinenti. Una volta verificata la sussistenza della violazione, questo sito rimuoverà immediatamente il contenuto sospetto di violazione.