主頁 > 移動端開發 > Android小專案--2048小游戲

Android小專案--2048小游戲

2020-12-31 12:10:10 移動端開發

Android小專案–2048小游戲

文章目錄

  • Android小專案--2048小游戲
    • 1.摘要
    • 2.實作的功能
    • 3.完成的界面展示
    • 4.功能具體實作的程序
      • 1. 游戲面板GameView的設計(采用GridLayout布局)
      • 2. Cell類的設計:Cell用來表示游戲中的小格子
      • 3. 將cell添加到GameView中:
      • 4. 游戲模式的改變:
      • 5. 記錄當前分數及歷史最高分數
      • 6. 判斷游戲是否結束
    • 5. 總結

1.摘要

現如今,電子游戲已慢慢滲透進人們生活中,并在扮演著越來越重的角色,2048小游戲屬于益智類小游戲,它做到了娛樂性、趣味性、教育性相統一,益智類的游戲即是需要去開動大腦去思考從而獲得游戲的勝利,簡單的益智類游戲可以使玩家在娛樂中不斷的開發大腦,這樣一來就實作了在娛樂中學習,

這篇文章主要為大家介紹了Android實作2048小游戲的相關內容,感興趣的小伙伴們可以參考一下!

2.實作的功能

  1. 確認布局
  2. UI界面
  3. 2048游戲邏輯的實作
  4. 游戲界面:
    • 基本的4×4格子
    • 擴展的5×5格子
    • 擴展的6×6格子
  5. 記錄當前得分和歷史最高分數
  6. 游戲模式:
    • 經典模式:達到2048即為“成功”,游戲結束,
    • 無限模式:沒有2048的上限,在沒有失敗的情況下,玩家可以一直玩下去.
  7. 最后游戲結束時“You Win!”或“You Lose!”的判定

3.完成的界面展示

!!在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

4.功能具體實作的程序

1. 游戲面板GameView的設計(采用GridLayout布局)

  • 先自定義一個GameView類,繼承GridLayout,添加兩個構造方法(GridLayout布局是Android 4.0新增的布局,引入該布局極大地方便了Grid型別的布局開發,不熟悉該布局的讀者朋友可以在Android開發者網站上尋找相關的開發資料進行學習)
public class GameView extends GridLayout {

 //兩個必要的構造方法
 public GameView(Context context) {
   super(context);
   initView();
 }

 public GameView(Context context, AttributeSet attrs) {
   super(context, attrs);
   initView();
 }
}
  • 在initView()中定義格子的寬和高,并且添加觸摸事件監聽
 public void initView(int mode) {
        gameMode = mode;
        canSwipe = true;
        // 移除所有視圖,以便更改游戲難度
        removeAllViews();
        // 初始化格子
        if (mode == Constant.MODE_CLASSIC) {
            // 經典模式
            gridColumnCount = Config.GRIDColumnCount;
        } else if (mode == Constant.MODE_INFINITE) {
            // 無限模式
            gridColumnCount = 6;
        }
        cells = new Cell[gridColumnCount][gridColumnCount];
        // 設定界面大小
        setColumnCount(gridColumnCount);
        // 獲取格子的寬
        int cellWidth = getCellSize();
        // 獲取格子的高
        int cellHeight = getCellSize();
        addCell(cellWidth, cellHeight);
        startGame();
        setOnTouchListener((v, event) -> {
            // 通知父控制元件不要攔截此控制元件的onTouch事件
            v.getParent().requestDisallowInterceptTouchEvent(true);
            if (canSwipe) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        setX = event.getX();
                        setY = event.getY();
                        break;
                    case MotionEvent.ACTION_UP:
                        offsetX = event.getX() - setX;
                        offsetY = event.getY() - setY;
                        // 判斷滑動方向
                        int orientation = getOrientation(offsetX, offsetY);
                        switch (orientation) {
                            case 0:
                                // 向右滑動
                                swipeRight();
                                break;
                            case 1:
                                // 向左滑動
                                swipeLeft();
                                break;
                            case 2:
                                // 向下滑動
                                swipeDown();
                                break;
                            case 3:
                                // 向上滑動
                                swipeUp();
                                break;
                            default:
                            break;
                        }
                    default:
                    break;
                }
            }
            return true;
        });
    }
  • 添加滑動事件(這里舉例上滑):
  • 簡要說一下此處實作的游戲玩法演算法:首先用for回圈一行一行地去遍歷每一個cell,然后從當前的位置往右去遍歷,判斷如果獲取到了某一個值不是空的,此時有兩種情況,一是當前位置上的值是空的,此時把獲取到的值放到當前位置上,同時把獲取到的位置上的數字清掉;二是當前位置上的值不是空的,并且獲取到的值和當前位置上的值相同,則把合并這兩個卡片,把當前位置上的值乘以二,同時把獲取到的位置上的數字清掉,
  • 還有一種情況是,如果我們當前位置上是空的,然后把右邊的值放到當前的位置上去了,此時繼續往后邊(右邊)去遍歷,后邊的位置還是空的,然后右邊又有一個數字和之前放過去的數字是一樣的情況的話,也是把它放到這個空位置上去了,這時會發生一個狀況:這兩張數字實際是一樣的,但是它們并不合并,為了避免這種情況的發生,我們再讓它去遍歷一次,即讓x-- ,這樣這個問題就解決了,
    //上滑事件
    private void swipeUp() {
        // 判斷是否需要添加數字
        boolean needAddDigital = false;
        for (int i = 0; i < gridColumnCount; i++) {
            for (int j = 0; j < gridColumnCount; j++) {
                // 獲取當前位置數字
                int currentDigital = cells[j][i].getDigital();
                someData.add(currentDigital);
                if (currentDigital != 0) {
                    // 記錄數字
                    if (recordPreviousDigital == -1) {
                        recordPreviousDigital = currentDigital;
                    } else {
                        // 記錄的之前的數字和當前數字不同
                        if (recordPreviousDigital != currentDigital) {
                            // 加入記錄的數字
                            dataAfterSwipe.add(recordPreviousDigital);
                            recordPreviousDigital = currentDigital;
                        } else {// 記錄的之前的數字和當前的數字相同
                            // 加入*2
                            dataAfterSwipe.add(recordPreviousDigital * 2);
                            // 記錄得分
                            recordScore(recordPreviousDigital * 2);
                            // 重置記錄數字
                            recordPreviousDigital = -1;
                        }
                    }
                }
            }

            if (recordPreviousDigital != -1) {
                dataAfterSwipe.add(recordPreviousDigital);
            }

            // 補0
            for (int p = dataAfterSwipe.size(); p < gridColumnCount; p++) {
                dataAfterSwipe.add(0);
            }
            // 若原始資料和移動后的資料不同,視為界面發生改變
            if (!someData.equals(dataAfterSwipe)) {
                needAddDigital = true;
            }
            someData.clear();

            // 重新設定格子資料
            for (int k = 0; k < dataAfterSwipe.size(); k++) {
                cells[k][i].setDigital(dataAfterSwipe.get(k));
            }
            // 重置資料
            recordPreviousDigital = -1;
            dataAfterSwipe.clear();
        }
        if (needAddDigital) {
            // 添加一個亂數字(2或4)
            addDigital(false);
            playSound();
        }
        judgeOverOrAccomplish();
    }
  • 判斷滑動方向:
 /**
     * 注:先依據在軸上滑動距離的大小,判斷在哪個軸上滑動
     * @param offsetX 在X軸上的移動距離
     * @param offsetY 在Y軸上的移動距離
     * @return 滑動方向
     * 注:0右滑、1左滑、2下滑、3上滑、-1未構成滑動
     */
    private int getOrientation(float offsetX, float offsetY) {
        // X軸移動
        if (Math.abs(offsetX) > Math.abs(offsetY)) {
            if (offsetX > MIN_DIS) {
                return 0;
            } else if (offsetX < -MIN_DIS) {
                return 1;
            } else {
                return -1;
            }
        } else {// Y軸移動
            if (offsetY > MIN_DIS) {
                return 2;
            } else if (offsetY < -MIN_DIS) {
                return 3;
            } else {
                return -1;
            }
        }
    }

2. Cell類的設計:Cell用來表示游戲中的小格子

  • Cell表示游戲中移動的小格子,格子的顏色、顯示數字等屬性都在物件中進行設定,Cell類如下:
public class Cell extends FrameLayout {

    //顯示數字的TextView
    private TextView cellShowText;

    //顯示的數字
    private int digital;

    public Cell(Context context) {
        super(context);
    }

    public Cell(@NonNull Context context, int leftMargin, int topMargin, int bottomMargin) {
        super(context);
        init(context, leftMargin, topMargin, bottomMargin);
    }

    //初始化
    private void init(@NonNull Context context, int leftMargin, int topMargin, int bottomMargin) {
        cellShowText = new TextView(context);
        // 不同難度設定不同字體大小
        switch (Config.GRIDColumnCount) {
            case 4:
                cellShowText.setTextSize(36);
                break;
            case 5:
                cellShowText.setTextSize(28);
                break;
            case 6:
                cellShowText.setTextSize(20);
                break;
            default:
                cellShowText.setTextSize(36);
                break;
        }
        cellShowText.setGravity(Gravity.CENTER);
        // 抗鋸齒
        cellShowText.getPaint().setAntiAlias(true);
        // 粗體
        cellShowText.getPaint().setFakeBoldText(true);
        // 顏色
        cellShowText.setTextColor(ContextCompat.getColor(context, R.color.colorWhite));
        // 填充整個父容器
        LayoutParams params = new LayoutParams(-1, -1);
        params.setMargins(leftMargin, topMargin, 0, bottomMargin);
        addView(cellShowText, params);
        setDigital(0);
    }

    //獲取卡片
    public TextView getItemCell() {
        return cellShowText;
    }

    //獲取數字
    public int getDigital() {
        return digital;
    }

    //設定數字
    public void setDigital(int digital) {
        this.digital = digital;
        cellShowText.setBackgroundResource(getBackgroundResource(digital));
        if (digital <= 0) {
            cellShowText.setText("");
        } else {
            cellShowText.setText(String.valueOf(digital));
        }
    }

    //根據數字獲取相應的背景
    private int getBackgroundResource(int number) {
        switch (number) {
            case 0:
                return R.drawable.bg_cell_0;
            case 2:
                return R.drawable.bg_cell_2;
            case 4:
                return R.drawable.bg_cell_4;
            case 8:
                return R.drawable.bg_cell_8;
            case 16:
                return R.drawable.bg_cell_16;
            case 32:
                return R.drawable.bg_cell_32;
            case 64:
                return R.drawable.bg_cell_64;
            case 128:
                return R.drawable.bg_cell_128;
            case 256:
                return R.drawable.bg_cell_256;
            case 512:
                return R.drawable.bg_cell_512;
            case 1024:
                return R.drawable.bg_cell_1024;
            case 2048:
                return R.drawable.bg_cell_2048;
            default:
                return R.drawable.bg_cell_default;
        }
    }
}

3. 將cell添加到GameView中:

  • 游戲初始化需要根據難度向GameView添加所有的Cell
    /**
     * 初始化向布局中添加空格子
     * @param cellWidth  格子寬
     * @param cellHeight 格子高
     */
    private void addCell(int cellWidth, int cellHeight) {
        Cell cell;
        for (int i = 0; i < gridColumnCount; i++) {
            for (int j = 0; j < gridColumnCount; j++) {
                if (i == gridColumnCount - 1) {
                    // 為最底下的格子加上bottomMargin
                    cell = new Cell(getContext(), 16, 16, 16);
                } else {
                    cell = new Cell(getContext(), 16, 16, 0);
                }
                cell.setDigital(0);
                addView(cell, cellWidth, cellHeight);
                cells[i][j] = cell;
            }
        }
    }
  • 所有格子需要獲取數字,最初全部設為0,即所有格子為空
    //獲取空格子
    private void getEmptyCell() {
        // 清空
        emptyCellPoint.clear();
        // 遍歷所有格子,記錄所有空格子的坐標位置
        for (int i = 0; i < gridColumnCount; i++) {
            for (int j = 0; j < gridColumnCount; j++) {
                // 空格子
                if (cells[i][j].getDigital() <= 0) {
                    emptyCellPoint.add(new Point(i, j));
                }
            }
        }
    }
  • 以4:6的概率隨機獲取一個數字2或4
    public void addDigital(boolean isCheat) {
        getEmptyCell();
        if (emptyCellPoint.size() > 0) {
            // 隨機取出一個空格子的坐標位置
            Point point = emptyCellPoint.get((int) (Math.random() * emptyCellPoint.size()));
            cells[point.x][point.y].setDigital(Math.random() > 0.4 ? 2 : 4);
            
            // 設定影片
            setAppearAnim(cells[point.x][point.y]);
        }
    }

4. 游戲模式的改變:

  • 擴展功能:無限模式和經典模式的切換:
    //打開切換模式對話框
    private void showChangeModeDialog() {
        String subject = "";
        if (Config.CurrentGameMode == Constant.MODE_CLASSIC) {
            subject = "無限模式";
        } else if (Config.CurrentGameMode == Constant.MODE_INFINITE) {
            subject = "經典模式";
        }
        CommonDialog dialog = new CommonDialog(this, R.style.CustomDialog);
        dialog.setCancelable(true);
        dialog.setTitle(getResources().getString(R.string.tip))
                .setMessage("是否要切換到" + subject)
                .setOnPositiveClickedListener("", v -> {
                    if (Config.CurrentGameMode == Constant.MODE_CLASSIC) {
                        Toast.makeText(GameActivity.this, "已進入無限模式", Toast.LENGTH_SHORT).show();
                        enterInfiniteMode();
                    } else {
                        Toast.makeText(GameActivity.this, "已進入經典模式", Toast.LENGTH_SHORT).show();
                        enterClassicsMode();
                    }
                    dialog.cancel();
                })
                .setOnNegativeClickListener("", v -> dialog.cancel())
                .show();
    }

    // 進入無限模式
    private void enterInfiniteMode() {
        Config.haveCheat = false;
        Config.CurrentGameMode = Constant.MODE_INFINITE;
        // 保存游戲模式
        ConfigManager.putCurrentGameMode(this, Constant.MODE_INFINITE);
        titleDescribe.setText(getResources().getString(R.string.game_mode_infinite));
        bestScores.setText(String.valueOf(ConfigManager.getBestScoreWithinInfinite(this)));
        bestScoresRank.setText(getResources().getText(R.string.tv_best_score_infinite));
        currentScores.setText(String.valueOf(ConfigManager.getCurrentScoreWithinInfinite(this)));
        modeDescribe.setText(getResources().getString(R.string.tv_describe_infinite));
        setTextStyle(titleDescribe);
        gameView.initView(Constant.MODE_INFINITE);
    }

    //進入經典模式
    private void enterClassicsMode() {
        Config.haveCheat = false;
        Config.CurrentGameMode = Constant.MODE_CLASSIC;
        // 保存游戲模式
        ConfigManager.putCurrentGameMode(this, Constant.MODE_CLASSIC);
        titleDescribe.setText(getResources().getString(R.string.game_mode_classics));
        // 讀取到歷史最高分
        bestScores.setText(String.valueOf(Config.BestScore));
        bestScoresRank.setText(getString(R.string.best_score_rank, Config.GRIDColumnCount));
        currentScores.setText(String.valueOf(ConfigManager.getCurrentScore(this)));
        modeDescribe.setText(getResources().getString(R.string.tv_describe));
        setTextStyle(titleDescribe);
        gameView.initView(Constant.MODE_CLASSIC);

    }

5. 記錄當前分數及歷史最高分數

    //記錄得分
    private void recordScore(int score) {
        currentScores.setText(String.valueOf(score));
        // 當前分數大于最高分
        if (Config.CurrentGameMode == Constant.MODE_CLASSIC) {
            if (score > ConfigManager.getBestScore(this)) {
                updateBestScore(score);
            }
        } else if (Config.CurrentGameMode == Constant.MODE_INFINITE) {
            if (score > ConfigManager.getBestScoreWithinInfinite(this)) {
                updateBestScore(score);
            }
        }
    }

    //更新歷史最高分
    private void updateBestScore(int newScore) {
        bestScores.setText(String.valueOf(newScore));
        if (Config.CurrentGameMode == Constant.MODE_CLASSIC) {
            Config.BestScore = newScore;
            ConfigManager.putBestScore(this, newScore);
        } else if (Config.CurrentGameMode == Constant.MODE_INFINITE) {
            Config.BestScoreWithinInfinite = newScore;
            ConfigManager.putBestScoreWithinInfinite(this, newScore);
        }
    }

6. 判斷游戲是否結束

  • 每次獲取數字時需要判斷游戲是否結束
    private void judgeOverOrAccomplish() {
        // 判斷游戲結束的標識
        boolean isOver = true;

        // 判斷游戲是否結束:格子都不為空且相鄰的格子數字不同
        over:
        for (int i = 0; i < gridColumnCount; i++) {
            for (int j = 0; j < gridColumnCount; j++) {
                // 有空格子,游戲還可以繼續
                if (cells[i][j].getDigital() == 0) {
                    isOver = false;
                    break over;
                }
                // 判斷左右上下有沒有相同的
                if (j < gridColumnCount - 1) {
                    if (cells[i][j].getDigital() == cells[i][j + 1].getDigital()) {
                        isOver = false;
                        break over;
                    }
                }
                if (i < gridColumnCount - 1) {
                    if (cells[i][j].getDigital() == cells[i + 1][j].getDigital()) {
                        isOver = false;
                        break over;
                    }
                }
            }
        }

        // 游戲結束,彈出提示框
        if (isOver) {
            canSwipe = false;
            sendGameOverMsg(ACTION_LOSE);
        }

        // 經典模式下才判贏
        if (gameMode == 0) {
            // 判斷是否達成游戲目標
            for (int i = 0; i < gridColumnCount; i++) {
                for (int j = 0; j < gridColumnCount; j++) {
                    // 有一個格子數字到達2048則視為達成目標
                    if (cells[i][j].getDigital() == 2048) {
                        canSwipe = false;
                        int currentTime = ConfigManager.getGoalTime(getContext()) + 1;
                        ConfigManager.putGoalTime(getContext(), currentTime);
                        Config.GetGoalTime = currentTime;
                        sendGameOverMsg(ACTION_WIN);
                    }
                }
            }
        }
    }

5. 總結

  • 涉及到的知識點匯總:
    • Sqlite
    • SharedPreferences
    • GestureOverlayView
    • Animation
    • Spannable
    • Handler
    • BroadcastReceiver
    • Timer
    • 自定義View
  • 本文代碼是根據極客學院2048小游戲代碼視頻一步步撰寫并完善實作,程序中遇到的困難主要是思考游戲思路和鍵盤事件的理解(即手指滑動時的事件),游戲思路在上文中滑動事件前已有詳細解釋,這里給出一個不錯的講解鍵盤事件的鏈接,有遇到相同困難的同學可以查看,
  • 鍵盤事件講解鏈接

作者:宋迎新
參考文章:參考文章
原文鏈接:原文鏈接

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

標籤:其他

上一篇:安卓學習筆記35:廣播接收者

下一篇:5張圖片解決android studio報錯:Failed to resolve: com.android.support:appcompat-v7:29

標籤雲
其他(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