主頁 > 移動端開發 > android 自定義 控制元件 旋轉選單 轉盤 rotatemenu java 原始碼

android 自定義 控制元件 旋轉選單 轉盤 rotatemenu java 原始碼

2021-03-04 11:11:35 移動端開發

話不多說看效果

在這里插入圖片描述

代碼在這里

public class YPPercentRotateMenuView extends View {

    private static final String TAG = "YPPercentRotateMenuView";

    Context context;

    public YPPercentRotateMenuView(Context context) {
        super(context);
        init(context);
    }

    public YPPercentRotateMenuView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public YPPercentRotateMenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    Paint paint;
    ArrayList<Item> items;

    //默認item顯示個數:7
    int itemCount = 7;

    //默認item尺寸與控制元件高度比值:.1
    float itemWidthR = .1f;

    //默認item最小最大尺寸比值:.5f
    float itemZoomR = .5f;

    //默認轉盤中心點到左邊緣距離與高度的比值:.1
    float centerOffsetR = .1f;

    //默認最靠近左邊緣的item中心到左邊緣距離與高度的比值:.1;(全稱:offset from center of item near edge to edge ratio)
    float oFCOINE2ER = .1f;

    //默認轉盤半徑與高度的比值:.3
    float radiusR = .3f;

    //默認文字尺寸與高度的比值:.04
    float textSizeR = .04f;

    //默認文字最小最大尺寸的比值:.7
    float textZoomR = .7f;

    //默認文字到圖示的距離與高度的比值:.015;(全稱:offset from text to item ratio)
    float oFT2I = .015f;

    //默認慣性起始速度倍率:16;(全稱:inertia origin speed ratio)
    float iOSR = 16;

    //默認慣性速度和修正角度衰減:.95
    float reduction = .95f;

    //默認慣性速度最小閾值:0.18°
    double inertiaThreshold = Math.PI / 100;

    //默認修正角度最小閾值:0.018°
    double correctThreshold = Math.PI / 1000;

    //默認慣性和修正繪制的間隔時間(毫秒):20
    long drawInterval = 20;

    void init(Context context) {
        this.context = context;
        handler = new Handler(context.getMainLooper());

        paint = new Paint();
        paint.setAntiAlias(true);

        paintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    }

    PaintFlagsDrawFilter paintFlagsDrawFilter;

    int width, height;

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getWidth();
        height = getHeight();
        if (items == null) {
            return;
        }
        invalidateValue();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (items == null) {
            return;
        }
        canvas.setDrawFilter(paintFlagsDrawFilter);
        //item和文字尺寸偏移量
        double itemSizeOffset = offsetRadian / intervalRadian * itemZoomGrad;
        double textSizeOffset = offsetRadian / intervalRadian * textZoomGrad;
        if (itemCountIsOdd) {
            //畫下半部分的item
            for (int i = 0; i < halfCount + 1; i++) {
                Item item = items.get(((i + index) % itemTotalCount + itemTotalCount) % itemTotalCount);
                Bitmap bitmap = item.getBitmap();
                String text = item.getText();
                int bw = bitmap.getWidth();
                int bh = bitmap.getHeight();

                //計算item的中心位置
                int x = (int) (radius * Math.cos(i * intervalRadian + offsetRadian) + centerOffset);
                int y = (int) (radius * Math.sin(i * intervalRadian + offsetRadian) + height / 2);

                //計算當前item大小的一半
                int currentHalfWidth = (int) (halfItemWidth * (1 - itemZoomGrad * i - (i == 0 ? Math.abs(itemSizeOffset) : itemSizeOffset)));
                if (isSelectItem) {
                    if (actionIndex - halfCount == i) {
                        currentHalfWidth = (int) (currentHalfWidth * .8);
                    }
                }

                //計算當前文字大小
                int currentTextSize = (int) (textSize * (1 - textZoomGrad * i - (i == 0 ? Math.abs(textSizeOffset) : textSizeOffset)));

                //畫item
                canvas.drawBitmap(bitmap, new Rect(0, 0, bw, bh), new Rect(x - currentHalfWidth, y - currentHalfWidth, x + currentHalfWidth, y + currentHalfWidth), paint);

                //畫文字
                paint.setTextSize(currentTextSize);
                canvas.drawText(text, x + currentHalfWidth + oft2i, y + currentTextSize / 2f, paint);
            }

            //畫上半部分item
            for (int i = 1; i < halfCount + 1; i++) {

                Item item = items.get(Math.abs((itemTotalCount - i + index % itemTotalCount) % itemTotalCount));
                Bitmap bitmap = item.getBitmap();
                String text = item.getText();
                int bw = bitmap.getWidth();
                int bh = bitmap.getHeight();

                //計算item的中心位置
                int x = (int) (radius * Math.cos(i * intervalRadian - offsetRadian) + centerOffset);
                int y = (int) (height / 2 - radius * Math.sin(i * intervalRadian - offsetRadian));

                //計算當前item大小的一半
                int currentHalfWidth = (int) (halfItemWidth * (1 - itemZoomGrad * i + itemSizeOffset));
                if (isSelectItem) {
                    if (actionIndex == halfCount - i) {
                        currentHalfWidth = (int) (currentHalfWidth * .8);
                    }
                }

                //計算當前文字大小
                int currentTextSize = (int) (textSize * (1 - textZoomGrad * i + textSizeOffset));

                //畫item
                canvas.drawBitmap(bitmap, new Rect(0, 0, bw, bh), new Rect(x - currentHalfWidth, y - currentHalfWidth, x + currentHalfWidth, y + currentHalfWidth), paint);

                //畫文字
                paint.setTextSize(currentTextSize);
                canvas.drawText(text, x + currentHalfWidth + oft2i, y + currentTextSize / 2f, paint);
            }
        } else {

            //畫下半部分的item
            for (int i = 0; i < halfCount; i++) {
                Item item = items.get(((i + index) % itemTotalCount + itemTotalCount) % itemTotalCount);
                Bitmap bitmap = item.getBitmap();
                String text = item.getText();
                int bw = bitmap.getWidth();
                int bh = bitmap.getHeight();

                //計算item的中心位置
                int x = (int) (radius * Math.cos((i + .5) * intervalRadian + offsetRadian) + centerOffset);
                int y = (int) (radius * Math.sin((i + .5) * intervalRadian + offsetRadian) + height / 2);

                //計算當前item大小的一半
                int currentHalfWidth = (int) (halfItemWidth * (1 - itemZoomGrad * i - itemSizeOffset));

                //計算當前文字大小
                int currentTextSize = (int) (textSize * (1 - textZoomGrad * i - textSizeOffset));
                if (isSelectItem) {
                    if (actionIndex - halfCount == i) {
                        currentHalfWidth = (int) (currentHalfWidth * .8);
                    }
                }

                //畫item
                canvas.drawBitmap(bitmap, new Rect(0, 0, bw, bh), new Rect(x - currentHalfWidth, y - currentHalfWidth, x + currentHalfWidth, y + currentHalfWidth), paint);

                //畫文字
                paint.setTextSize(currentTextSize);
                canvas.drawText(text, x + currentHalfWidth + oft2i, y + currentTextSize / 2f, paint);
            }

            //畫上半部分的item
            for (int i = 0; i < halfCount; i++) {

                Item item = items.get(Math.abs((itemTotalCount - i - 1 + index % itemTotalCount) % itemTotalCount));
                Bitmap bitmap = item.getBitmap();
                String text = item.getText();
                int bw = bitmap.getWidth();
                int bh = bitmap.getHeight();

                //計算item的中心位置
                int x = (int) (radius * Math.cos((i + .5) * intervalRadian - offsetRadian) + centerOffset);
                int y = (int) (height / 2 - radius * Math.sin((i + .5) * intervalRadian - offsetRadian));

                //計算當前item大小的一半
                int currentHalfWidth = (int) (halfItemWidth * (1 - itemZoomGrad * i + itemSizeOffset));
                if (isSelectItem) {
                    if (actionIndex == halfCount - i - 1) {
                        currentHalfWidth = (int) (currentHalfWidth * .8);
                    }
                }

                //計算當前文字大小
                int currentTextSize = (int) (textSize * (1 - textZoomGrad * i + textSizeOffset));

                //畫item
                canvas.drawBitmap(bitmap, new Rect(0, 0, bw, bh), new Rect(x - currentHalfWidth, y - currentHalfWidth, x + currentHalfWidth, y + currentHalfWidth), paint);

                //畫文字
                paint.setTextSize(currentTextSize);
                canvas.drawText(text, x + currentHalfWidth + oft2i, y + currentTextSize / 2f, paint);
            }
        }
    }

    boolean itemCountIsOdd;
    int itemTotalCount, halfItemWidth, centerOffset, radius, oFCOINE2E, textSize, oft2i, halfCount;
    float itemZoomGrad, textZoomGrad, intervalRadian;
    double aCos, radianOfItemNearEdge, halfItemSpanRadian;

    void invalidateValue() {
        itemTotalCount = items.size();//item集合總數
        itemCount = Math.min(itemCount, itemTotalCount);//避免item集合總輸比應顯示item數少
        itemCountIsOdd = itemCount % 2 == 1;//判斷顯示item數奇偶性
        halfItemWidth = (int) (height * itemWidthR / 2);//item原始寬度
        centerOffset = (int) (height * centerOffsetR);//轉盤中心偏移量
        radius = (int) (height * radiusR);//轉盤半徑
        oFCOINE2E = (int) (height * oFCOINE2ER);//最靠邊item中心偏移量
        textSize = (int) (height * textSizeR);//原始text尺寸
        oft2i = (int) (height * oFT2I);//text與item間距離
        aCos = Math.acos((oFCOINE2E - centerOffset) / (float) radius);//最靠邊item中心與左邊0°夾角
        radianOfItemNearEdge = Math.PI - aCos;//最靠邊item中心與右邊0°夾角
        halfItemSpanRadian = Math.sin((double) halfItemWidth / radius);//半個item弧度跨度

        if (itemCountIsOdd) {
            halfCount = (itemCount - 1) / 2;//顯示item數一半
            intervalRadian = (float) (aCos / halfCount);//單個間隔弧度
        } else {
            halfCount = itemCount / 2;
            intervalRadian = (float) (aCos / (halfCount - .5));
        }

        itemZoomGrad = (1 - itemZoomR) / (halfCount);//item縮放梯度
        textZoomGrad = (1 - textZoomR) / (halfCount);//text縮放梯度
    }

    double moveRadian_before, moveRadian_after, speed;

    double downRadian;

    int index = 0;
    int actionIndex = -1;
    boolean isSelectItem = false;

    double currentRadian = 0;
    double markRadian = 0;

    double offsetRadian = 0;

    Handler handler;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        handler.removeCallbacks(inertiaNCorrectTask);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //記錄按下位置
                downRadian = calculateRadian(event.getX(), event.getY());

                actionIndex = getActionItem(event.getX(), event.getY());
                if (actionIndex != -1 && offsetRadian == 0) {
                    isSelectItem = true;
                    invalidate();
                }
                return true;
            case MotionEvent.ACTION_MOVE:
                //當前弧度數 = 標記弧度 + 滑動弧度
                currentRadian = downRadian - calculateRadian(event.getX(), event.getY()) + markRadian;

                calculateNInvalidate();

                if (actionIndex != getActionItem(event.getX(), event.getY())) {
                    isSelectItem = false;
                }

                //記錄滑動位置
                moveRadian_before = moveRadian_after;
                moveRadian_after = calculateRadian(event.getX(), event.getY());
                break;

            case MotionEvent.ACTION_UP:
                //更新標記弧度數
                markRadian = downRadian - calculateRadian(event.getX(), event.getY()) + markRadian;

                if (isSelectItem) {
                    isSelectItem = false;
                    invalidate();
                    int i = (actionIndex - halfCount + index % itemTotalCount + itemTotalCount) % itemTotalCount;
                    Log.e(TAG, "onTouchEvent: 點擊了:" + i);
                    if (listener != null) {
                        listener.onSelect(i);
                    }
                }
                currentRadian = markRadian;
                speed = (moveRadian_before - moveRadian_after) * iOSR;
                moveRadian_before = 0;
                moveRadian_after = 0;
                handler.post(inertiaNCorrectTask);

                break;
        }
        return super.onTouchEvent(event);
    }

    Runnable inertiaNCorrectTask = new Runnable() {
        @Override
        public void run() {
            if (Math.abs(speed) > inertiaThreshold && !isSelectItem) {
                currentRadian = currentRadian + speed;
                speed = speed * reduction;
                calculateNInvalidate();
                markRadian = currentRadian;
                handler.postDelayed(this, drawInterval);
            } else {
                if (offsetRadian != 0) {
                    if (Math.abs(offsetRadian) < correctThreshold) {
                        currentRadian = currentRadian + offsetRadian;
                    } else {
                        currentRadian = currentRadian + offsetRadian * (1 - reduction);
                    }
                    markRadian = currentRadian;
                    calculateNInvalidate();
                    postDelayed(this, drawInterval);
                }
            }
        }
    };

    int getActionItem(float x, float y) {
        if (isInCircle(x, y, radius + halfItemWidth) && !isInCircle(x, y, radius - halfItemWidth)) {
            double actionRadian = calculateRadian(x, y);
            int i = (int) ((actionRadian - (radianOfItemNearEdge - halfItemSpanRadian)) / intervalRadian);
            if (actionRadian < radianOfItemNearEdge + intervalRadian * i + halfItemSpanRadian && actionRadian > radianOfItemNearEdge + intervalRadian * i - halfItemSpanRadian) {
                return i;
            }
        }
        return -1;
    }

    boolean isInCircle(float x, float y, float radius) {
        return Math.sqrt(Math.pow((x - centerOffset), 2) + Math.pow((y - height / 2), 2)) <= radius;
    }

    void calculateNInvalidate() {
        //計算居中item序號
        double a = currentRadian > 0 ? .5 * intervalRadian : -.5f * intervalRadian;
        index = (int) ((currentRadian + a) / intervalRadian);

        //計算item偏移弧度
        double tempOffsetRadian = BigDecimal.valueOf(currentRadian % intervalRadian).doubleValue();
        if (Math.abs(tempOffsetRadian) < intervalRadian / 2) {
            offsetRadian = -tempOffsetRadian;
        } else {
            if (tempOffsetRadian > 0) {
                offsetRadian = intervalRadian - tempOffsetRadian;
            } else {
                offsetRadian = -tempOffsetRadian - intervalRadian;
            }
        }
        invalidate();
    }

    double calculateRadian(float x, float y) {
        double chord = Math.sqrt(Math.pow(x - centerOffset, 2) + Math.pow(y - height / 2, 2));
        if (y > height / 2) {
            return Math.acos((x - centerOffset) / chord) + Math.PI;
        } else {
            return Math.PI - Math.acos((x - centerOffset) / chord);
        }
    }


    public void setItems(ArrayList<Item> items) {
        this.items = items;
        invalidateValue();
        invalidate();
    }

    private OnSelectInterface listener;

    public void setListener(OnSelectInterface listener) {
        this.listener = listener;
    }

    public interface OnSelectInterface {
        void onSelect(int i);
    }

    public static class Item {
        Bitmap bitmap;
        String text;

        public Item(Bitmap bitmap, String text) {
            this.bitmap = bitmap;
            this.text = text;
        }

        public Bitmap getBitmap() {
            return bitmap;
        }

        public String getText() {
            return text;
        }
    }
}

怎么用

1.先把上面的類添加到你的專案里

在這里插入圖片描述

2.實體一個轉盤控制元件

  • 在xml里面實體:

	<com.ns.myrotatemenuapplication.YPPercentRotateMenuView
			android:id="@+id/ypprmv"
	        android:layout_width="match_parent"
	        android:layout_height="match_parent"/>
        
  • 在代碼中實體:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        YPPercentRotateMenuView ypprmv = new YPPercentRotateMenuView(this);
        ypprmv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        setContentView(ypprmv);
    }
    
  • 注意:無論在哪里實體,必須要指定寬高,所有屬性都是根據控制元件高度決定

3.定義轉盤屬性


public class YPPercentRotateMenuView extends View {

	···

	//默認item顯示個數:7
    int itemCount = 7;

    //默認item尺寸與控制元件高度比值:.1
    float itemWidthR = .1f;

    //默認item最小最大尺寸比值:.5f
    float itemZoomR = .5f;

    //默認轉盤中心點到左邊緣距離與高度的比值:.1
    float centerOffsetR = .1f;

    //默認最靠近左邊緣的item中心到左邊緣距離與高度的比值:.1;(全稱:offset from center of item near edge to edge ratio)
    float oFCOINE2ER = .1f;

    //默認轉盤半徑與高度的比值:.3
    float radiusR = .3f;

    //默認文字尺寸與高度的比值:.04
    float textSizeR = .04f;

    //默認文字最小最大尺寸的比值:.7
    float textZoomR = .7f;

    //默認文字到圖示的距離與高度的比值:.015;(全稱:offset from text to item ratio)
    float oFT2I = .015f;

    //默認慣性起始速度倍率:16;(全稱:inertia origin speed ratio)
    float iOSR = 16;

    //默認慣性速度和修正角度衰減:.95
    float reduction = .95f;

    //默認慣性速度最小閾值:0.18°
    double inertiaThreshold = Math.PI / 100;

    //默認修正角度最小閾值:0.018°
    double correctThreshold = Math.PI / 1000;

    //默認慣性和修正繪制的間隔時間(毫秒):20
    long drawInterval = 20;
    
    ···
}
  • 把上面代碼的數字改改,適應你們的設計圖
  • 當然,原始碼都在這了,想怎么改就怎么改,主要是改paint的屬性,其他的繪制最好還是不要動,我自己寫的代碼,都已經看不懂了,可見計算有多復雜

4.設定轉盤資料

  • 設定item和文字

      ArrayList<YPPercentRotateMenuView.Item> items = new ArrayList<>();
      Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ic);
      for (int i = 0; i < 20; i++) {
          items.add(new YPPercentRotateMenuView.Item(bitmap, "item" + i));
      }
      ypprmv.setItems(items);
    
  • 設定點擊事件

      ypprmv.setListener(new YPPercentRotateMenuView.OnSelectInterface() {
          @Override
          public void onSelect(int i) {
              switch (i){
                  ···
              }
          }
      });

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

標籤:其他

上一篇:Android 開發 AIDL 使用demo

下一篇:Coordinatorlayout嵌套滑動,自定義Behavior,聽我來講講?

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