首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 自定義 ViewGroup 實現百度紅包福袋解鎖界面

     編輯:Java 相關知識

效果預覽

9 宫格圖片點阵,手指滑動連線,經過的圖片縮放動畫、繪製圓點與連線,鬆開 1 秒後自動清除軌跡。核心技術:自定義 ViewGroup 佈局 + 手勢繪製 View 疊加。

架構設計

  • LYJViewGroup:繼承 ViewGroup,負責 9 張圖片均勻佈局(onLayout、onMeasure)
  • LYJGestureView:繼承 View,疊加在 ViewGroup 上方,負責觸摸事件、Canvas 繪製連線/圓點、縮放動畫回調
  • LYJGesturePoint:資料類,記錄每個圖片的邊界矩形、中心點、選中狀態
  • LYJCirclePoint:資料類,記錄繪製圓點的中心與半徑

核心實作精華

1. ViewGroup 等分佈局


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    for (int i = 0; i < getChildCount(); i++) {
        int row = i / 3, col = i % 3;
        View v = getChildAt(i);
        int left = col * cellWidth + cellWidth / BASE_NUM;
        int top = row * cellWidth + cellWidth / BASE_NUM;
        int right = left + cellWidth - 2 * cellWidth / BASE_NUM;
        int bottom = top + cellWidth - 2 * cellWidth / BASE_NUM;
        v.layout(left, top, right, bottom);
    }
}

2. 觸摸事件狀態機


@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            currentPoint = getPointAt(event.getX(), event.getY());
            if (currentPoint != null) {
                selectPoint(currentPoint);
                drawCircle(currentPoint);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            clearAndRedraw(); // 重繪已確認軌跡
            LYJGesturePoint next = getPointAt(event.getX(), event.getY());
            if (next != null && next != currentPoint && !next.isSelected()) {
                // 移動到新點:畫線、標記、動畫
                drawLine(currentPoint, next);
                selectPoint(next);
                animationCallback.startAnimation(next.getIndex());
                currentPoint = next;
            } else {
                // 移動到空白/同點:畫臨時線到手指位置
                drawTempLine(currentPoint, event.getX(), event.getY());
            }
            break;
        case MotionEvent.ACTION_UP:
            clearAndRedraw(); // 移除臨時線
            new Handler().postDelayed(this::clearAll, 1000); // 1秒後清空
            break;
    }
    invalidate();
    return true;
}

3. Canvas 雙緩衝繪製


// 建構子建立 Bitmap + Canvas
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas();
canvas.setBitmap(bitmap);

// 繪製邏輯寫在 onTouchEvent,僅操作離屏 Canvas
// onDraw 僅負責將 Bitmap 畫到螢幕
@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(bitmap, 0, 0, null);
}

4. 縮放動畫回調


public interface OnAnimationCallback {
    void startAnimationImage(int index);
}

// ViewGroup 實作
@Override
public void startAnimationImage(int index) {
    Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.scale_anim);
    getChildAt(index).startAnimation(anim);
}

關鍵技術點總結

技術點實作要點
點擊判定遍歷 9 個矩形區域,x in [left,right) && y in [top,bottom)
軌跡保存兩個列表:lineList (Pair) + circlePoints
重繪策略每次 canvas.drawColor(CLEAR) 後遍歷列表重畫
離屏緩衝Bitmap + Canvas 避免 onDraw 重複計算,效能大幅提升
動畫解耦介面回調讓 ViewGroup 控制子 View 動畫

擴充建議

  • 支援 N×M 任意網格(動態計算 cellWidth)
  • 加入觸覺回饋(Vibrator)
  • 軌跡驗證邏輯(正則表達式/最短路徑/最小步數)
  • 使用 Path 替代逐段 drawLine,支援平滑曲線
  • Kotlin 重寫 + 協程簡化延遲清理邏輯

結語

百度紅包界面看似複雜,實則是「佈局容器 + 手勢繪製層 + 狀態機」的經典組合。掌握 ViewGroup.onLayout、Canvas 雙緩衝、觸摸事件分發 三大核心,即可舉一反三實現手勢密碼、連連看、軌跡繪圖等多種互動效果。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved