主頁 > 移動端開發 > Android 漸變的‘TabLayout’ , (含免費( java / kotlin) Demo)

Android 漸變的‘TabLayout’ , (含免費( java / kotlin) Demo)

2021-08-13 07:55:18 移動端開發

?? : 本篇‘由簡入奢’,全是干貨!

  • 繪制文字與BaseLine思考
  • 文字居中
  • 裁剪
  • 從左到右漸變文字
  • 從右到左漸變文字
  • 最終實作效果(漸變滑動)
  • 過度繪制極限優化

先來看看完成的效果:


簡單解釋: 在滑動的程序中,漸變文字會隨著ViewPager的滑動而變化!!

繪制文字與BaseLine思考

先來看看最初版代碼:

public class GradualChangeTv extends AppCompatTextView {
    public Paint mPaint = new Paint();

    public final String text = "android 超級兵";

    public GradualChangeTv(Context context) {
        this(context, null);
    }

    public GradualChangeTv(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GradualChangeTv(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint.setColor(Color.RED);
        //抗鋸齒
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, 0, 0, mPaint);
    }
}

就是簡單的繪制了一行字

疑問:

  • 為什么這里要繼承自AppCompatTextView 而不是View

    答: 偷個懶而已,因為不用在我來測量View,直接用父類的就行

來看看效果順便也看看布局:

出現問題: 文字并沒有顯示
答:因為文字坐標系和螢屏坐標系不一樣,文字坐標系是從BaseLine線開始計算的

先來回顧一下螢屏的坐標系


在來看看文字的坐標系
(圖片來自于網路)

再來思考一下文字是為什么不顯示的:

  • 虛線為BaseLine

如果此時我把字體放大到100,看一看我能不能看到文字


再一次證明了文字是從BaseLine線開始繪制

文字居中

可以用兩條輔助線,水平線與垂直線.然后在來看文字是否居中

代碼:

?? : 底部會給出完整代碼.這里看思路即可,不用復制代碼

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //獲取當前控制元件的寬高
        int viewWidth = getWidth() / 2;
        int viewHeight = getHeight() / 2;
        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, viewWidth, viewHeight, mPaint);

        //繪制居中線
        drawCenterLine(canvas, viewWidth, viewHeight);
    }

    private void drawCenterLine(Canvas canvas, int viewWidth, int viewHeight) {
        //垂直線
        canvas.drawLine(viewWidth, 0, viewWidth, getHeight(), mPaint);

        //水平線
        canvas.drawLine(0,viewHeight,getWidth(),viewHeight,mPaint);
    }

效果圖:


可以看出,還是上面說的那個問題,文字繪制是基于baseLine線來繪制的.

文字居中思路:

  • 通過mPaint.measureText(text) 獲取文字寬
  • 通過mPaint.descent() + mPaint.ascent(); 獲取文字高
  • 然后控制元件各取一半,讓控制元件減去即可

這里的descent和ascent可以參考上面文字繪制圖

相關代碼:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //文字寬度
        float textWidth = mPaint.measureText(text);
        //文字高度
        float textHeight = mPaint.descent() + mPaint.ascent();

        //獲取當前控制元件的寬高
        int viewWidth = getWidth() / 2;
        int viewHeight = getHeight() / 2;

        canvas.drawText(text, viewWidth - textWidth / 2, viewHeight - textHeight / 2, mPaint);

        //繪制居中線
        drawCenterLine(canvas, viewWidth, viewHeight);
    }

效果圖:


裁剪

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //文字寬度
        float textWidth = mPaint.measureText(text);
        //文字高度
        float textHeight = mPaint.descent() + mPaint.ascent();

        //獲取當前控制元件的寬高的一半
        int viewWidth = getWidth() / 2;
        int viewHeight = getHeight() / 2;

        //裁剪
        drawClip(canvas, viewWidth, viewHeight, textWidth, textHeight);

        //繪制居中線
        drawCenterLine(canvas, viewWidth, viewHeight);
    }

    private void drawClip(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
        mPaint.setColor(Color.BLACK);
        canvas.save();
        //繪制文字X軸的位置
        float left = viewWidth - textWidth / 2;

        //繪制文字Y軸的位置
        float right = viewHeight - textHeight / 2;

        //裁剪
        canvas.clipRect((int) left, 0, (int) left + 300, getHeight());

        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, left, right, mPaint);

        canvas.restore();
    }

裁剪(clipRect)引數分析:

  • 引數一: 從文字開始位置繪制
  • 引數二: 頂部裁剪為0
  • 引數三: 裁剪寬度
  • 引數四: 繪制高度

canvas.save(),和canvas.restore();方法

可以理解為:將當前繪制的東西當作一個新的圖層!

來看看效果圖:

代碼注釋很清晰;就不過多解釋了

從左到右漸變文字

眾所周知.在android中,是不能夠將文字繪制一般的

思路分析:

  • 繪制兩層(兩層顏色不同),兩層疊加起來
  • 然后通過裁剪將上面一層給裁剪掉

在來看看現在代碼是什么樣子的:

   //用來記錄當前進度 【0-1】
    float progress = 0.3f;
    
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //文字寬度
        float textWidth = mPaint.measureText(text);
        //文字高度
        float textHeight = mPaint.descent() + mPaint.ascent();

        //獲取當前控制元件的寬高的一半
        int viewWidth = getWidth() / 2;
        int viewHeight = getHeight() / 2;

        //繪制底層
        drawBottom(canvas, viewWidth, viewHeight, textWidth, textHeight);

        //繪制上層【顏色漸變的】
        drawUp(canvas, viewWidth, viewHeight, textWidth, textHeight);

        //繪制居中線
        drawCenterLine(canvas, viewWidth, viewHeight);
    }

    //繪制上層【漸變的】
    private void drawUp(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
        mPaint.setColor(Color.BLACK);
        canvas.save();
        //繪制文字X軸的位置
        float left = viewWidth - textWidth / 2;

        //繪制文字Y軸的位置
        float right = viewHeight - textHeight / 2;

        //裁剪
        canvas.clipRect((int) left, 0, (int) left + textWidth * progress, getHeight());

        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, left, right, mPaint);

        canvas.restore();
    }

    //繪制下層 不動的
    private void drawBottom(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
        mPaint.setColor(Color.RED);  //文字顏色
        canvas.save();
		//文字開始位置
        float left = viewWidth - textWidth / 2;

        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, left, viewHeight - textHeight / 2, mPaint);
        canvas.restore();
    }

這里重點解釋一下上層[需要裁剪的]引數:

 //裁剪
canvas.clipRect((int) left, 0, (int) left + textWidth * progress, getHeight());
  • textWidth 需要繪制文字的寬度
  • viewWidth 控制元件寬度的一半
  • 文字開始的位置:left = viewWidth - textWidth / 2;
  • 文字需要裁剪的位置: 文字的寬度 * progress

通過手勢滑動來控制:

這段代碼并沒有實質性作用,只是來看看效果:

@SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            progress = event.getX() / getWidth();
            invalidate();
        }
        return true;
    }

效果圖:


從右到左漸變文字

思路和從左到右繪制是一樣的直接看關鍵代碼:

private void drawRightToLeft(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
        mPaint.setColor(Color.GREEN);
        /*
         * 這里 left和right能夠在此抽取出來,不過這樣寫很易懂,有需求自己弄吧!!!
         */
        canvas.save();
        //繪制文字X軸的位置 【文字開始的位置】
        float textX = viewWidth - textWidth / 2;

        //繪制文字Y軸的位置
        float textY = viewHeight - textHeight / 2;

        //文字結束的位置
        float end = viewWidth + mPaint.measureText(text) / 2;

        canvas.clipRect(end, 0, textX + textWidth * (1 - progress), getHeight());

        canvas.drawText(text, textX, textY, mPaint);
        canvas.restore();
    }

@SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (type == GradualChangeTextView.GRADUAL_CHANGE_RIGHT) {
                //從右到左滑動
                progress = 1 - event.getX() / getWidth();
            } else if (type == GradualChangeTextView.GRADUAL_CHANGE_LEFT) {
                //從左到右滑動
                progress = event.getX() / getWidth();
            }
            invalidate();
        }
        return true;
    }

效果圖:


最后在添加兩個按鈕來完全測驗一下代碼有沒有問題:

完完全全沒有問題!

最終實作效果(漸變滑動)

先來看看布局:

在這里插入圖片描述
布局簡單的很,就是文字和ViewPager

大致看看ViewPager代碼:

 //text1 .. text4 是控制元件id
        val textList = listOf(text1, text2, text3, text4)

        val list = listOf(HomeFragment(), MyFragment(), TestFragment(), SettingFragment())

        val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager, list)

        viewPager.adapter = viewPagerAdapter

        //默認選擇第一頁
        viewPager.currentItem = 1

        //默認選中
        textList[viewPager.currentItem].percent = 1f

這段代碼,只要學過就懂,不細說了!

重中之重來了:

viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int,
            ) {
                if (positionOffset > 0) {
                    val left = textList[position]
                    val right = textList[position + 1]
                    //從右到左滑動
                    left.setSlidingPosition(GradualChangeTextView.GRADUAL_CHANGE_RIGHT)
                    //從左到右滑動
                    right.setSlidingPosition(GradualChangeTextView.GRADUAL_CHANGE_LEFT)

					//當前頁面取反[從右到左]
                    left.percent = 1 - positionOffset
                    //下一個頁面正常[從左到右]
                    right.percent = positionOffset
                }
            }

            override fun onPageSelected(position: Int) { }

            override fun onPageScrollStateChanged(state: Int) {
                //當 ViewPage結束的時候,重新設定一下狀態 [不設定的話滑動太快,會導致'殘影']
                textList.forEach {
                    if (it.tag == textList[viewPager.currentItem].tag) {
                        it.percent = 1f
                    } else {
                        it.percent = 0f
                    }
                }
            }
        })

來看看效果:


過度繪制極限優化

什么是過度繪制:

參考檔案

重點總結:

  • 1.原色 – 沒有被過度繪制 – 這部分的像素點只在螢屏上繪制了一次,
  • 2.藍色 – 1次過度繪制– 這部分的像素點只在螢屏上繪制了兩次,
  • 3.綠色 – 2次過度繪制 – 這部分的像素點只在螢屏上繪制了三次,
  • 4.粉色 – 3次過度繪制 – 這部分的像素點只在螢屏上繪制了四次,
  • 5.紅色 – 4次過度繪制 – 這部分的像素點只在螢屏上繪制了五次,

先來看看沒有優化的效果:

可以看到,在繪制的程序中,因為是兩層,那么就繪制了2次,

優化思路:
當黑色[上層]從左到右滑動的時候,紅色[下層]跟隨著從左到右裁剪

來看看下層繪制的代碼:

//繪制下層 不動的
    private void drawBottom(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
        mPaint.setColor(Color.RED);
        canvas.save();
        //繪制文字X軸的位置 [文字開始的位置]
        float textX = viewWidth - textWidth / 2;

        //繪制文字Y軸的位置
        float textY = viewHeight - textHeight / 2;

        //跟隨者上層裁剪
        canvas.clipRect((int) textX + textWidth * progress, 0, textWidth + viewWidth, getHeight());
        /*
         * 繪制文字
         * 引數一: 繪制文字
         * 引數二: x軸開始位置
         * 引數三: y 軸開始位置
         * 引數四: 畫筆
         */
        canvas.drawText(text, textX, textY, mPaint);
        canvas.restore();
    }

效果圖:

完整代碼

原創不易,您的點贊就是對我最大的支持!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/293390.html

標籤:其他

上一篇:騰訊社招Android 崗面經分享,僥幸斬獲Offer

下一篇:Android 語音提示

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more