Androidのカスタムビュー:FMは目盛りを実装

レンダリング

序文

ラジオは、最近のプロジェクトをやっても、既存のオープンソースのライブラリについて考えを始め、FMスケールを描画する必要があるが、後に見つかったが、彼女は自分のバーを描画することを決定したUI弟を、満たすことが要求されていません。デモは、上記のような効果を得ます。中小主ワイヤの3つの長さを含むスケール、スケールインジケータの整数部。FMスケールのこの完璧な実現。ここでは大まかに具体的な実践を紹介。ただまっすぐに行くことができるコードの学生を見てGithubの住所

描画開始

私は、継承を介していたView、関連するクラスのカスタムビューのリライトを達成するために。最も重要なことは、3つの関連するメソッドを実装することです:

  • onMeasure():ビューの役割はどのくらいのスペースのニーズを測定することです
  • onDraw():様々な形状を描きます
  • onTouchEvent():タッチイベントを処理

onMeasureを書き直し()

)(onMeasure()オーバーライドして、親クラスonMeasureを呼び出すとき:

  • RulerView layout_widthと属性値がlayout_height wrap_contentをmatch_parentや表示サイズが親コントロールによって決定されます。
  • RulerViewは、固定値、セットのために表示された値に設定します。
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(setMeasureWidth(widthMeasureSpec), setMeasureHeight(heightMeasureSpec));
    }

    private int setMeasureHeight(int spec) {
        int mode = MeasureSpec.getMode(spec);
        int size = MeasureSpec.getSize(spec);
        int result = Integer.MAX_VALUE;
        switch (mode) {
            case MeasureSpec.AT_MOST:
                size = Math.min(result, size);
                break;
            case MeasureSpec.EXACTLY:
                break;
            default:
                size = result;
                break;
        }
        return size;
    }

    private int setMeasureWidth(int spec) {
        int mode = MeasureSpec.getMode(spec);
        int size = MeasureSpec.getSize(spec);
        int result = Integer.MAX_VALUE;
        switch (mode) {
            case MeasureSpec.AT_MOST:
                size = Math.min(result, size);
                break;
            case MeasureSpec.EXACTLY:
                break;
            default:
                size = result;
                break;
        }
        return size;
    }
复制代码

説明

MeasureSpec.getSizeは()親コンテナの幅や高さにMeasureSpec価値を解析します。

MeasureSpec.getMode()int型3種類の値があり得る:MeasureSpec.EXACTLY MeasureSpec.AT_MOST、MeasureSpec.UNSPECIFIED。

  • 指定されていないMeasureSpec.UNSPECIFIED、サイズは任意に設定することができます。
  • MeasureSpec.AT_MOST:RulerViewは任意のサイズにすることができますが、限界があります。
  • MeasureSpec.EXACTLY:親コンテナは、親コンテナの範囲の限度内で、MeasureExampleViewサイズを決定MeasureExampleViewサイズです。

onDrawリライト()

まず、我々はブラシを初期化する必要があります

private Paint mLinePaint;//刻度线画笔
private Paint mTextPaint;//指示数字画笔
private Paint mRulerPaint;//指示线画笔

private void init() {
        mLinePaint = new Paint();
        mLinePaint.setColor(getResources().getColor(R.color.grey));
        //抗锯齿
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setStrokeWidth(1);

        mTextPaint = new Paint();
        mTextPaint.setColor(getResources().getColor(R.color.grey));
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setStrokeWidth(2);
        mTextPaint.setTextSize(24);

        mRulerPaint = new Paint();
        mRulerPaint.setAntiAlias(true);
        mRulerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mRulerPaint.setColor(getResources().getColor(R.color.ruler_line));
        mRulerPaint.setStrokeWidth(3);
    }
复制代码

描画を開始:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        //绘制刻度线
        for (int i = min; i <= max; i++) {
            if (i % 10 == 0) {
                canvas.drawLine(20, 0, 20, 140, mLinePaint);

                String text = i / 10 + "";
                Rect rect = new Rect();
                float txtWidth = mTextPaint.measureText(text);
                mTextPaint.getTextBounds(text, 0, text.length(), rect);
                if (i / 10 % 2 == 1 && i / 10 != 107) {
                    canvas.drawText(text, 20 - txtWidth / 2, 72 + rect.height() + 74, mTextPaint);
                }
                if (i / 10 == 108) {
                    canvas.drawText(text, 20 - txtWidth / 2, 72 + rect.height() + 74, mTextPaint);
                }
            } else if (i % 5 == 0) {
                canvas.drawLine(20, 30, 20, 110, mLinePaint);
            } else {
                canvas.drawLine(20, 54, 20, 86, mLinePaint);
            }
            canvas.translate((float) 8, 0);
        }
        canvas.restore();

        //绘制指示线
        canvas.drawLine(position, 0, position, 140, mRulerPaint);
        mTextPaint.setTextSize(24);
    }
复制代码

上記のコードは、3つの異なる目盛、数字の長さ、及び指標線の規模のために示されています。だから我々は、図面の縮尺を完了しました。一つだけスケールが十分ではありません。しかし、我々はまた、イベントをクリックしてスライドするonTouchEvent応答を書き換える必要があります。我々は、スライドもモニタインタフェースの対応する対を定義する際に得られた対応する値をスケーリングする必要がある場合。

onTouchEventを書き直し()

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                if (x < MIN_POSITION) {
                    setPosition(MIN_POSITION);
                } else if (x > MAX_POSITION) {
                    setPosition(MAX_POSITION);
                } else {
                    setPosition((int) x);
                }
                //移动指示条
                if (mMove != null) {
                    mMove.onMove(Double.parseDouble(String.format("%.1f", getFmChannel())));
                }
                Log.d("TAG", "position:" + position);
                Log.d("TAG", "channel:" + getFmChannel());
            case MotionEvent.ACTION_CANCEL:
                //只停在0.1(刻度线上)的位置
                setFmChanel(Double.parseDouble(String.format("%.1f", getFmChannel())));
                Log.d("停下来后", "channel:" + Double.parseDouble(String.format("%.1f", getFmChannel())));
                break;
            default:
        }
        return true;
    }
    
    public void setPosition(int i) {
        position = i;
        invalidate();
    }

    public void setFmChanel(double fmChanel) {
        int temp = (int) ((fmChanel - 87) * 80) + 20;
        setPosition(temp);
    }

    public double getFmChannel() {
        return ((position - 20.0) / 80.0 + 87.0);
    }

复制代码

だから我々がスリップできることを示すインジケータは、スケールアップのための尺度です。私は、問題が発生したスケールでViewPagerでこのプロセスを使用します。スムーズに摺動拡張することはできませんアップ。これは、親コントロールとためである紛争のスライドイベントのみ上書きする必要があるdispatchTouchEventメソッドを次のように、解決することができます。

   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //解决刻度尺和viewPager的滑动冲突
        //当滑动刻度尺时,告知父控件不要拦截事件,交给子view处理
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }
复制代码

我々はスライディングスケールのリアルタイム値を監視する必要がある場合は、適切なリスナーインタフェースを設定する必要があります。コードは以下の通りであります:

  /**
     * 定义监听接口
     */
    public interface OnMoveActionListener {
        void onMove(double x);
    }

    /**
     * 为每个接口设置监听器
     */
    public void setOnMoveActionListener(OnMoveActionListener move) {
        mMove = move;
    }
复制代码

これはリアルタイムで監視摺動可能なインジケータダイヤルゲージ値を実現し、規模の特定の値にジャンプします。

概要

スライド描画やイベント処理などのダニに関連する要素の全体規模を実現。スケール線画がトラブルに見える限り、実際の明確なアイデアとして、対応するラインの長さに応じた位置に描画されます。スケールは貧しい、貧しい学生が回改定の基礎で使用できる拡張性を言及しました。

GitHubの:github.com/gs666/Rulerは...〜問題とスターを言及するのを歓迎します

デンバーホーム:juejin.im/user/5bffbd ...歓迎の注意〜

ます。https://juejin.im/post/5d0afe1f51882508be27a504で再現

おすすめ

転載: blog.csdn.net/weixin_34292402/article/details/93178222