Android 自定義ListView Item側滑刪除

本程序是基於網上開源項目修改而來,具體來源忘了,懶得搜了,如果有不合適的地方,請原作者聯繫我,我會及時回覆和處理的!

該例子程序中主要包含兩個ListView,一個是實現側滑刪除,一個是側滑出菜單,代碼中的註釋很全,我就不在贅述了,直接貼上核心代碼和效果圖。

側滑刪除ListView:

 


002.package com.example.testslidelistview;
003.import android.content.Context;
004.import android.util.AttributeSet;
005.import android.view.MotionEvent;
006.import android.view.VelocityTracker;
007.import android.view.View;
008.import android.view.ViewConfiguration;
009.import android.view.WindowManager;
010.import android.widget.AdapterView;
011.import android.widget.ListView;
012.import android.widget.Scroller;
013. 
014./**
015.* 側滑刪除Item的ListView,此處是對網上開源的一個Listview的完善,
016.* 實現在手指滑動時item的透明度隨之改變,並增加回到原位置的動畫過程
017.* @author zhangshuo
018.*/
019.public class SlideListView extends ListView {
020./**
021.* 當前滑動的ListView position
022.*/
023.private int slidePosition;
024./**
025.* 手指按下X的座標
026.*/
027.private int downY;
028./**
029.* 手指按下Y的座標
030.*/
031.private int downX;
032./**
033.* 屏幕寬度
034.*/
035.private int screenWidth;
036./**
037.* ListView的item
038.*/
039.private View itemView;
040./**
041.* 滑動類
042.*/
043.private Scroller scroller;
044.private static final int SNAP_VELOCITY = 600;
045./**
046.* 速度追蹤對象
047.*/
048.private VelocityTracker velocityTracker;
049./**
050.* 是否響應滑動,默認爲不響應
051.*/
052.private boolean isSlide = false;
053./**
054.* 認爲是用戶滑動的最小距離
055.*/
056.private int mTouchSlop;
057./**
058.*  移除item後的回調接口
059.*/
060.private RemoveListener mRemoveListener;
061./**
062.*  標示是否移除
063.*/
064.private boolean isRemove = false;
065./**
066.* 用來指示item滑出屏幕的方向,向左或者向右,用一個枚舉值來標記
067.*/
068.private RemoveDirection removeDirection;
069. 
070.// 滑動刪除方向的枚舉值
071.public enum RemoveDirection {
072.RIGHT, LEFT, NONE;
073.}
074. 
075. 
076.public SlideListView(Context context) {
077.this(context, null);
078.}
079. 
080.public SlideListView(Context context, AttributeSet attrs) {
081.this(context, attrs, 0);
082.}
083. 
084.public SlideListView(Context context, AttributeSet attrs, int defStyle) {
085.super(context, attrs, defStyle);
086.screenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
087.scroller = new Scroller(context);
088.mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
089.}
090. 
091./**
092.* 設置滑動刪除的回調接口
093.* @param removeListener
094.*/
095.public void setRemoveListener(RemoveListener removeListener) {
096.this.mRemoveListener = removeListener;
097.}
098. 
099./**
100.* 分發事件,主要做的是判斷點擊的是那個item, 以及通過postDelayed來設置響應左右滑動事件
101.*/
102.@Override
103.public boolean dispatchTouchEvent(MotionEvent event) {
104.switch (event.getAction()) {
105.case MotionEvent.ACTION_DOWN: {
106.System.out.println("dispatch-->" "down");
107.addVelocityTracker(event);
108. 
109.// 假如scroller滾動還沒有結束,我們直接返回
110.if (!scroller.isFinished()) {
111.return false;
112.}
113.downX = (int) event.getX();
114.downY = (int) event.getY();
115. 
116.slidePosition = pointToPosition(downX, downY);
117. 
118.// 無效的position, 不做任何處理
119.if (slidePosition == AdapterView.INVALID_POSITION) {
120.return super.dispatchTouchEvent(event);
121.}
122. 
123.// 獲取我們點擊的item view
124.itemView = getChildAt(slidePosition - getFirstVisiblePosition());
125.break;
126.}
127.case MotionEvent.ACTION_MOVE: {
128.System.out.println("dispatch-->" "move");
129.if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY
130.|| (Math.abs(event.getX() - downX) > mTouchSlop && Math
131..abs(event.getY() - downY) < mTouchSlop)) {
132.isSlide = true;
133. 
134.}
135.break;
136.}
137.case MotionEvent.ACTION_UP:
138.recycleVelocityTracker();
139.break;
140.}
141. 
142.return super.dispatchTouchEvent(event);
143.}
144. 
145./**
146.* 往右滑動,getScrollX()返回的是左邊緣的距離,就是以View左邊緣爲原點到開始滑動的距離,所以向右邊滑動爲負值
147.*/
148.private void scrollRight() {
149.removeDirection = RemoveDirection.RIGHT;
150.final int delta = (screenWidth + itemView.getScrollX());
151.// 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item
152.scroller.startScroll(itemView.getScrollX(), 0, -delta, 0,
153.Math.abs(delta));
154.postInvalidate(); // 刷新itemView
155.}
156. 
157./**
158.* 向左滑動,根據上面我們知道向左滑動爲正值
159.*/
160.private void scrollLeft() {
161.removeDirection = RemoveDirection.LEFT;
162.final int delta = (screenWidth - itemView.getScrollX());
163.// 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item
164.scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
165.Math.abs(delta));
166.postInvalidate(); // 刷新itemView
167.}
168. 
169./**
170.*  滑動會原來的位置
171.*/
172.private void scrollBack(){
173.removeDirection = RemoveDirection.NONE;
174.scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(), 0,
175.Math.abs(itemView.getScrollX()));
176.postInvalidate(); // 刷新itemView
177.}
178. 
179./**
180.* 根據手指滾動itemView的距離來判斷是滾動到開始位置還是向左或者向右滾動
181.*/
182.private void scrollByDistanceX() {
183.// 如果向左滾動的距離大於屏幕的二分之一,就讓其刪除
184.if (itemView.getScrollX() >= screenWidth / 2) {
185.scrollLeft();
186.else if (itemView.getScrollX() <= -screenWidth / 2) {
187.scrollRight();
188.else {
189.// 滾回到原始位置
190.scrollBack();
191.}
192. 
193.}
194. 
195./**
196.* 處理我們拖動ListView item的邏輯
197.*/
198.@Override
199.public boolean onTouchEvent(MotionEvent ev) {
200.if (isSlide && slidePosition != AdapterView.INVALID_POSITION) {
201.System.out.println("touch-->" "開始");
202.requestDisallowInterceptTouchEvent(true);
203.addVelocityTracker(ev);
204.final int action = ev.getAction();
205.int x = (int) ev.getX();
206.switch (action) {
207.case MotionEvent.ACTION_DOWN:
208.System.out.println("touch-->" "down");
209.break;
210.case MotionEvent.ACTION_MOVE:
211.System.out.println("touch-->" "move");
212.MotionEvent cancelEvent = MotionEvent.obtain(ev);
213.cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
214.(ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
215.onTouchEvent(cancelEvent);
216. 
217.int deltaX = downX - x;
218. 
219.// 手指拖動itemView滾動, deltaX大於0向左滾動,小於0向右滾
220.itemView.scrollTo(deltaX, 0);
221.// 根據手指滑動的距離,調整透明度
222.itemView.setAlpha(1f - Math.abs((float)deltaX/screenWidth));
223. 
224.return true;  //拖動的時候ListView不滾動
225.case MotionEvent.ACTION_UP:
226.System.out.println("touch-->" "up");
227.// 手指離開的時候就不響應左右滾動
228.isSlide = false;
229.int velocityX = getScrollVelocity();
230.if (velocityX > SNAP_VELOCITY) {
231.scrollRight();
232.else if (velocityX < -SNAP_VELOCITY) {
233.scrollLeft();
234.else {
235.scrollByDistanceX();
236.}
237. 
238.recycleVelocityTracker();
239. 
240.break;
241.}
242.}
243. 
244.//否則直接交給ListView來處理onTouchEvent事件
245.return super.onTouchEvent(ev);
246.}
247. 
248.@Override
249.public void computeScroll() {
250.// 調用startScroll的時候scroller.computeScrollOffset()返回true,
251.if (scroller.computeScrollOffset()) {
252.// 讓ListView item根據當前的滾動偏移量進行滾動
253.itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());
254. 
255.itemView.setAlpha(1f - Math.abs((float)scroller.getCurrX()/screenWidth));
256. 
257.postInvalidate();
258. 
259.// 滾動動畫結束的時候調用回調接口
260.if (scroller.isFinished() && removeDirection != RemoveDirection.NONE) {
261.if (mRemoveListener == null) {
262.throw new NullPointerException("RemoveListener is null, we should called setRemoveListener()");
263.}
264.itemView.scrollTo(00);
265.itemView.setAlpha(1f);
266.mRemoveListener.removeItem(removeDirection, slidePosition);
267.}
268.}
269.}
270. 
271./**
272.* 添加用戶的速度跟蹤器
273.*
274.* @param event
275.*/
276.private void addVelocityTracker(MotionEvent event) {
277.if (velocityTracker == null) {
278.velocityTracker = VelocityTracker.obtain();
279.}
280. 
281.velocityTracker.addMovement(event);
282.}
283. 
284./**
285.* 移除用戶速度跟蹤器
286.*/
287.private void recycleVelocityTracker() {
288.if (velocityTracker != null) {
289.velocityTracker.recycle();
290.velocityTracker = null;
291.}
292.}
293. 
294./**
295.* 獲取X方向的滑動速度,大於0向右滑動,反之向左
296.*
297.* @return
298.*/
299.private int getScrollVelocity() {
300.velocityTracker.computeCurrentVelocity(1000);
301.int velocity = (int) velocityTracker.getXVelocity();
302.return velocity;
303.}
304. 
305./**
306.*
307.* 當ListView item滑出屏幕,回調這個接口
308.* 我們需要在回調方法removeItem()中移除該Item,然後刷新ListView
309.*
310.* @author xiaanming
311.*
312.*/
313.public interface RemoveListener {
314.public void removeItem(RemoveDirection direction, int position);
315.}
316. 
317.}
側滑菜單ListView:

 

 

001.package com.example.testslidelistview;
002. 
003.import android.content.Context;
004.import android.util.AttributeSet;
005.import android.view.MotionEvent;
006.import android.view.View;
007.import android.view.ViewConfiguration;
008.import android.widget.AdapterView;
009.import android.widget.ListView;
010.import android.widget.Scroller;
011. 
012./**
013.* 側向滑出菜單的ListView
014.* 使用請注意與ListView的Item的佈局配合,
015.* 該效果的實現是基於在Item的佈局中通過設置PaddingLeft和PaddingRight來隱藏左右菜單的,
016.* 所以使用此ListView時,請務必在佈局Item時使用PaddingLeft和PaddingRight;
017.* 或者自己改寫此ListView,已達到想要的實現方式
018.* @author zhangshuo
019.*/
020.public class SlideListView2 extends ListView {
021. 
022./**禁止側滑模式*/
023.public static int MOD_FORBID = 0;
024./**從左向右滑出菜單模式*/
025.public static int MOD_LEFT = 1;
026./**從右向左滑出菜單模式*/
027.public static int MOD_RIGHT = 2;
028./**左右均可以滑出菜單模式*/
029.public static int MOD_BOTH = 3;
030./**當前的模式*/
031.private int mode = MOD_FORBID;
032./**左側菜單的長度*/
033.private int leftLength = 0;
034./**右側菜單的長度*/
035.private int rightLength = 0;
036. 
037./**
038.* 當前滑動的ListView position
039.*/
040.private int slidePosition;
041./**
042.* 手指按下X的座標
043.*/
044.private int downY;
045./**
046.* 手指按下Y的座標
047.*/
048.private int downX;
049./**
050.* ListView的item
051.*/
052.private View itemView;
053./**
054.* 滑動類
055.*/
056.private Scroller scroller;
057./**
058.* 認爲是用戶滑動的最小距離
059.*/
060.private int mTouchSlop;
061. 
062./**
063.* 判斷是否可以側向滑動
064.*/
065.private boolean canMove = false;
066./**
067.* 標示是否完成側滑
068.*/
069.private boolean isSlided = false;
070. 
071.public SlideListView2(Context context) {
072.this(context, null);
073.}
074. 
075.public SlideListView2(Context context, AttributeSet attrs) {
076.this(context, attrs, 0);
077.}
078. 
079.public SlideListView2(Context context, AttributeSet attrs, int defStyle) {
080.super(context, attrs, defStyle);
081.scroller = new Scroller(context);
082.mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
083.}
084. 
085./**
086.* 初始化菜單的滑出模式
087.* @param mode
088.*/
089.public void initSlideMode(int mode){
090.this.mode = mode;
091.}
092. 
093./**
094.* 處理我們拖動ListView item的邏輯
095.*/
096.@Override
097.public boolean onTouchEvent(MotionEvent ev) {
098. 
099.final int action = ev.getAction();
100.int lastX = (int) ev.getX();
101. 
102.switch (action) {
103.case MotionEvent.ACTION_DOWN:
104.System.out.println("touch-->" "down");
105. 
106./*當前模式不允許滑動,則直接返回,交給ListView自身去處理*/
107.if(this.mode == MOD_FORBID){
108.return super.onTouchEvent(ev);
109.}
110. 
111.// 如果處於側滑完成狀態,側滑回去,並直接返回
112.if (isSlided) {
113.scrollBack();
114.return false;
115.}
116.// 假如scroller滾動還沒有結束,我們直接返回
117.if (!scroller.isFinished()) {
118.return false;
119.}
120.downX = (int) ev.getX();
121.downY = (int) ev.getY();
122. 
123.slidePosition = pointToPosition(downX, downY);
124. 
125.// 無效的position, 不做任何處理
126.if (slidePosition == AdapterView.INVALID_POSITION) {
127.return super.onTouchEvent(ev);
128.}
129. 
130.// 獲取我們點擊的item view
131.itemView = getChildAt(slidePosition - getFirstVisiblePosition());
132. 
133./*此處根據設置的滑動模式,自動獲取左側或右側菜單的長度*/
134.if(this.mode == MOD_BOTH){
135.this.leftLength = -itemView.getPaddingLeft();
136.this.rightLength = -itemView.getPaddingRight();
137.}else if(this.mode == MOD_LEFT){
138.this.leftLength = -itemView.getPaddingLeft();
139.}else if(this.mode == MOD_RIGHT){
140.this.rightLength = -itemView.getPaddingRight();
141.}
142. 
143.break;
144.case MotionEvent.ACTION_MOVE:
145.System.out.println("touch-->" "move");
146. 
147.if (!canMove
148.&& slidePosition != AdapterView.INVALID_POSITION
149.&& (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev
150..getY() - downY) < mTouchSlop)) {
151.int offsetX = downX - lastX;
152.if(offsetX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)){
153./*從右向左滑*/
154.canMove = true;
155.}else if(offsetX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)){
156./*從左向右滑*/
157.canMove = true;
158.}else{
159.canMove = false;
160.}
161./*此段代碼是爲了避免我們在側向滑動時同時出發ListView的OnItemClickListener時間*/
162.MotionEvent cancelEvent = MotionEvent.obtain(ev);
163.cancelEvent
164..setAction(MotionEvent.ACTION_CANCEL
165.| (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
166.onTouchEvent(cancelEvent);
167.}
168.if (canMove) {
169./*設置此屬性,可以在側向滑動時,保持ListView不會上下滾動*/
170.requestDisallowInterceptTouchEvent(true);
171. 
172.// 手指拖動itemView滾動, deltaX大於0向左滾動,小於0向右滾
173.int deltaX = downX - lastX;
174.if(deltaX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)){
175./*向左滑*/
176.itemView.scrollTo(deltaX, 0);
177.}else if(deltaX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)){
178./*向右滑*/
179.itemView.scrollTo(deltaX, 0);
180.}else{
181.itemView.scrollTo(00);
182.}
183.return true// 拖動的時候ListView不滾動
184.}
185.case MotionEvent.ACTION_UP:
186.System.out.println("touch-->" "up");
187.if (canMove){
188.canMove = false;
189.scrollByDistanceX();
190.}
191.break;
192.}
193. 
194.// 否則直接交給ListView來處理onTouchEvent事件
195.return super.onTouchEvent(ev);
196.}
197. 
198./**
199.* 根據手指滾動itemView的距離來判斷是滾動到開始位置還是向左或者向右滾動
200.*/
201.private void scrollByDistanceX() {
202./*當前模式不允許滑動,則直接返回*/
203.if(this.mode == MOD_FORBID){
204.return;
205.}
206.if(itemView.getScrollX() > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)){
207./*從右向左滑*/
208.if (itemView.getScrollX() >= rightLength / 2) {
209.scrollLeft();
210.}  else {
211.// 滾回到原始位置
212.scrollBack();
213.}
214.}else if(itemView.getScrollX() < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)){
215./*從左向右滑*/
216.if (itemView.getScrollX() <= -leftLength / 2) {
217.scrollRight();
218.else {
219.// 滾回到原始位置
220.scrollBack();
221.}
222.}else{
223.// 滾回到原始位置
224.scrollBack();
225.}
226. 
227.}
228. 
229./**
230.* 往右滑動,getScrollX()返回的是左邊緣的距離,就是以View左邊緣爲原點到開始滑動的距離,所以向右邊滑動爲負值
231.*/
232.private void scrollRight() {
233.isSlided = true;
234.final int delta = (leftLength + itemView.getScrollX());
235.// 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item
236.scroller.startScroll(itemView.getScrollX(), 0, -delta, 0,
237.Math.abs(delta));
238.postInvalidate(); // 刷新itemView
239.}
240. 
241./**
242.* 向左滑動,根據上面我們知道向左滑動爲正值
243.*/
244.private void scrollLeft() {
245.isSlided = true;
246.final int delta = (rightLength - itemView.getScrollX());
247.// 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item
248.scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
249.Math.abs(delta));
250.postInvalidate(); // 刷新itemView
251.}
252. 
253./**
254.* 滑動會原來的位置
255.*/
256.private void scrollBack() {
257.isSlided = false;
258.scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(),
259.0, Math.abs(itemView.getScrollX()));
260.postInvalidate(); // 刷新itemView
261.}
262. 
263.@Override
264.public void computeScroll() {
265.// 調用startScroll的時候scroller.computeScrollOffset()返回true,
266.if (scroller.computeScrollOffset()) {
267.// 讓ListView item根據當前的滾動偏移量進行滾動
268.itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());
269. 
270.postInvalidate();
271.}
272.}
273. 
274./**
275.* 提供給外部調用,用以將側滑出來的滑回去
276.*/
277.public void slideBack() {
278.this.scrollBack();
279.}
280. 
281.}

注意側滑菜單ListView的使用需要配合Item佈局(主要是PaddingLeft和PaddingRight這兩個屬性),Item佈局如下:

 

 

001.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
003.android:layout_width="match_parent"
004.android:layout_height="match_parent"
005.android:paddingLeft="-181dp"
006.android:paddingRight="-180dp"
007.android:background="@color/wheat"
008.android:orientation="horizontal" >
009. 
010.<LinearLayout
011.android:id="@+id/llayout_left"
012.android:layout_width="180dp"
013.android:layout_height="match_parent" >
014. 
015.<RelativeLayout
016.android:id="@+id/delete1"
017.android:layout_width="90dp"
018.android:layout_height="match_parent"
019.android:background="@color/slategray"
020.android:clickable="true" >
021. 
022.<TextView
023.android:layout_width="wrap_content"
024.android:layout_height="wrap_content"
025.android:layout_centerInParent="true"
026.android:gravity="center"
027.android:text="左刪除"
028.android:textColor="@color/floralwhite"
029.android:textSize="15sp" />
030.</RelativeLayout>
031. 
032.<RelativeLayout
033.android:id="@+id/other1"
034.android:layout_width="90dp"
035.android:layout_height="match_parent"
036.android:background="@color/tomato"
037.android:clickable="true" >
038. 
039.<TextView
040.android:layout_width="wrap_content"
041.android:layout_height="wrap_content"
042.android:layout_centerInParent="true"
043.android:gravity="center"
044.android:text="左其他"
045.android:textColor="@color/floralwhite"
046.android:textSize="15sp" />
047.</RelativeLayout>
048.</LinearLayout>
049. 
050. 
051.<RelativeLayout
052.android:layout_width="match_parent"
053.android:layout_height="match_parent">
054.<LinearLayout
055.android:layout_width="match_parent"
056.android:layout_height="match_parent"
057.android:layout_toLeftOf="@+id/llayout_right"
058.android:orientation="vertical" >
059. 
060.<TextView
061.android:id="@+id/title"
062.android:layout_width="match_parent"
063.android:layout_height="wrap_content"
064.android:gravity="center_vertical"
065.android:paddingLeft="10dp"
066.android:paddingRight="10dp"
067.android:text="標題"
068.android:textColor="@color/orange"
069.android:textSize="17sp" />
070. 
071.<TextView
072.android:id="@+id/time"
073.android:layout_width="wrap_content"
074.android:layout_height="wrap_content"
075.android:layout_marginLeft="10dp"
076.android:text="時間"
077.android:textColor="@color/black"
078.android:textSize="13sp" />
079. 
080.<TextView
081.android:id="@+id/content"
082.android:layout_width="wrap_content"
083.android:layout_height="wrap_content"
084.android:layout_marginLeft="10dp"
085.android:text="內容"
086.android:textColor="@color/black"
087.android:textSize="13sp" />
088.</LinearLayout>
089. 
090.<LinearLayout
091.android:id="@+id/llayout_right"
092.android:layout_width="180dp"
093.android:layout_height="match_parent"
094.android:layout_alignParentRight="true" >
095. 
096.<RelativeLayout
097.android:id="@+id/other2"
098.android:layout_width="90dp"
099.android:layout_height="match_parent"
100.android:background="@color/slategray"
101.android:clickable="true" >
102. 
103.<TextView
104.android:layout_width="wrap_content"
105.android:layout_height="wrap_content"
106.android:layout_centerInParent="true"
107.android:gravity="center"
108.android:text="右其他"
109.android:textColor="@color/floralwhite"
110.android:textSize="15sp" />
111.</RelativeLayout>
112. 
113.<RelativeLayout
114.android:id="@+id/delete2"
115.android:layout_width="90dp"
116.android:layout_height="match_parent"
117.android:background="@color/tomato"
118.android:clickable="true" >
119. 
120.<TextView
121.android:layout_width="wrap_content"
122.android:layout_height="wrap_content"
123.android:layout_centerInParent="true"
124.android:gravity="center"
125.android:text="右刪除"
126.android:textColor="@color/floralwhite"
127.android:textSize="15sp" />
128.</RelativeLayout>
129.</LinearLayout>
130.</RelativeLayout>
131. 
132. 
133.</LinearLayout>

截圖:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章