味と色について2-RGBシングルではありません

すべての読者への挨拶。 私たちの冒険を続けてみよう。その始まりはここにある



そのため、ユーザーが選択した色を引き出す必要があるマルチカラーの円のあるカスタムビューがあります。 計算のジャングルに飛び込む前に、選択した色のマーカーマーカーをいくつか整理しましょう。 複雑にせず、単純な線、つまり矢印の形にします。 そのためには、新しいペイントと寸法が必要です。 将来繰り返さないために、必要なすべてのパラメーターを一度に計算しましょう。 明確にするために、意図的に多数の個別の変数を作成します。



宣言とメソッドの形式は次のとおりです。



// ,         protected static final int SET_COLOR = 0; protected static final int SET_SATUR = 1; protected static final int SET_ALPHA = 2; //  ,        . // (-   ) private int mMode; float cx; float cy; float rad_1; // float rad_2; // float rad_3; // float r_centr; //    float r_sel_c; // float r_sel_s; // float r_sel_a; //    //   private Paint p_color = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint p_satur = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint p_alpha = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint p_white = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint p_handl = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint p_centr = new Paint(Paint.ANTI_ALIAS_FLAG); private float deg_col; //   private float deg_sat; //  -  private float deg_alp; // ******************** private float lc; // private float lm; //     private float lw; // private void calcSizes() { // // cx = size * 0.5f; cy = cx; lm = size * 0.043f; lw = size * 0.035f; rad_1 = size * 0.44f; r_sel_c = size * 0.39f; rad_2 = size * 0.34f; r_sel_s = size * 0.29f; rad_3 = size * 0.24f; r_sel_a = size * 0.19f; r_centr = size * 0.18f; lc = size * 0.08f; p_color.setStrokeWidth(lc); p_satur.setStrokeWidth(lc); p_alpha.setStrokeWidth(lc); }
      
      







まず、外側のリングの色を選択することを確認する必要があります。 これを行うには、中心から水平および垂直までの距離の座標(コードではACTION_DOWNのaおよびb)に、もう1つ-中心からの距離を直線で追加します。 ジオメトリのすべての法則により、「c」と呼びます。 そして、ピタゴラスの市民の作品を思い出しながら計算します:



 float c = (float) Math.sqrt(a * a + b * b);
      
      







ここで、接触点が外側のリング上にあること、つまりリングの内側の半径が大きいことを確認する必要があります。 同時に、将来を見据えて、まだ存在しない残りのリングに対してこれらのチェックを実行します。 そして、フラグを設定します。 最終的に:



  case MotionEvent.ACTION_DOWN: float a = Math.abs(event.getX() - cx); float b = Math.abs(event.getY() - cy); float c = (float) Math.sqrt(a * a + b * b); if (c > r_sel_c) mode = SET_COLOR; else if (c < r_sel_c && c > r_sel_s) mode = SET_SATUR; else if (c < r_sel_s && c > r_sel_a) mode = SET_ALPHA; else if (c < r_centr) listener.onDismiss(mColor, alpha); break;
      
      







注-ACTION_DOWNでのみ、中心からの距離チェックを実行します。 つまり、指を外側のリングに突っ込むことで、色選択ゾーンの外側であってもビューで好きなだけクロールできます。色が変わるのは色です。 もう一度指を突いて、モードフラグを変更するまで。



ACTION_MOVEで新しい座標を受け取り、選択した色、彩度、透明度を決定します。 onTouchを詰まらせないために、個別の方法で計算を行います。 それでは、invalidate()を呼び出します。ここに置く方が良いと思います。 私たちは成功しました:



  case MotionEvent.ACTION_MOVE: float x = event.getX() - cx; float y = event.getY() - cy; switch (mMode) { case SET_COLOR: setColScale(getAngle(x, y)); break; case SET_SATUR: setSatScale(getAngle(x, y)); break; case SET_ALPHA: setAlphaScale(getAngle(x, y)); break; } invalidate(); break; }
      
      







ツーインワン方式。 さらに詳しく考えてみましょう。 getAngle(x、y)-座標に基づいて、指の位置とビューの中心の間の角度を決定します。 このようなもの:



  protected float getAngle(float x, float y) { float deg = 0; if (x != 0) deg = y / x; deg = (float) Math.toDegrees(Math.atan(deg)); if (x < 0) deg += 180; else if (x > 0 && y < 0) deg += 360; return deg; }
      
      







出力では、角度を度単位で取得します。この角度は、グラデーションのこのセクターの色に何らかの形で関連付ける必要があります。 この考えで、行き詰まりました。 私はピクセルの座標を計算し、色を分析するという誤った考えをすぐに拒否しました。 マダガスカルからのペンギンの言葉-「コワルスキー、オプションを提案してください...」は私の頭の中で展開されました。 GoogleはKowalskiの役割を果たしました。 そして、ここに彼が言ったことがあります。



他の惑星に生命が存在することがわかりました。 そして、このようなネイティブで理解可能なARGBの代わりに、奇妙なHSVを使用します。 これはどんな獣ですか? たとえば、彼の最初の手紙は? Wikiは、これは「色相-色相... 0〜360の間で変化する」と主張しています。 偶然だろうか? そして、残りの文字は? S-彩度-はい、これは2番目のリングです! そして、V-値は明るさです。 Androidはすぐにいくつかの機能を提供します。



 Color.HSVToColor(int, float[]); Color.colorToHSV(int, float[]);
      
      







最初の関数のintパラメーターは透明度です。3番目のリングを思い出してください。 2番目の関数では、intは色そのものです。 また、両方の関数で、float []は3つの要素の配列です。最初の要素は、HSVの文字によると、0から360までのパレットの色の値です。生活は良くなっているようです。



argbおよびhsv配列を宣言して、色のコンポーネントを保存します。



  private int[] argb = new int[] { 255, 0, 0, 0}; private float[] hsv = new float[] {0, 1f, 1f};
      
      







そして、配列の最初の要素として度で取得した角度を置き換えます。



  protected void setColScale(float f) { deg_col = f; hsv[0] = f; mColor = Color.HSVToColor(argb[0], hsv); p_center.setColor(mColor); }
      
      







これで、2番目のリングと矢印を描くための色、角度、完全な権利が得られました。 コードは次のとおりです。



  private void drawSaturGradient(Canvas c) { SweepGradient s = null; int[] sg = new int[] { Color.HSVToColor(new float[] {deg_col, 1, 0}), Color.HSVToColor(new float[] {deg_col, 1, 1}), Color.HSVToColor(new float[] { hsv[0], 0, 1}), Color.HSVToColor(new float[] { hsv[0], 0, 0.5f}), Color.HSVToColor(new float[] {deg_col, 1, 0}) }; s = new SweepGradient(cx, cy, sg, null); p_satur.setShader(s); c.drawCircle(cx, cy, rad_2, p_satur); }
      
      







前のコードと非常によく似ていて、シェーダーと同じ配列、同じグラデーションです。 今だけ5つの色があり、それぞれがHSVから引き裂かれています。 さらに、彩度と明るさを手動で0から1に設定し、何らかの理由で角度の値を配列の最初の(ゼロの意味で)要素に入れました。 そこにある値hsv [0]を確認する方が正しいでしょうが、これはまったく同じ量です。 証拠として、私は2つの場所でフェリーさえしました。 deg_col == hsv [0]であることを忘れないでください。 まあ、最初の角度が私の腕に来ました、ごめんなさい。



結果:



画像



このメソッドは、次のようにonDraw()で呼び出す必要があることを誰もが理解していると思います。 ダダ、すでに3番目のリングを描くことができます。



  private void drawAlphaGradient(Canvas c) { //           //    c.drawCircle(cx, cy, rad_3 - lw, p_white); c.drawCircle(cx, cy, rad_3, p_white); c.drawCircle(cx, cy, rad_3 + lw, p_white); //   RGB    int ir = Color.red(mColor); int ig = Color.green(mColor); int ib = Color.blue(mColor); //     –       int e = Color.argb(0, ir, ig, ib); int[] mCol = new int[] {mColor, e}; //     Shader sw = new SweepGradient(cx, cy, mCol, null); p_alpha.setShader(sw); c.drawCircle(cx, cy, rad_3, p_alpha); }
      
      







そして矢印:



  private void drawLines(Canvas c) { float d = deg_col; c.rotate(d, cx, cy); c.drawLine(cx + rad_1 + lm, cy, cx + rad_1 - lm, cy, p_handl); c.rotate(-d, cx, cy); d = deg_sat; c.rotate(d, cx, cy); c.drawLine(cx + rad_2 + lm, cy, cx + rad_2 - lm, cy, p_handl); c.rotate(-d, cx, cy); d = deg_alp; c.rotate(d, cx, cy); c.drawLine(cx + rad_3 + lm, cy, cx + rad_3 - lm, cy, p_handl); c.rotate(-d, cx, cy); }
      
      







誰かに質問がありました-なぜ最後のメソッドでローカル変数dを使うのですか? おそらく、これらは私の妄想の兆候です。 グローバル変数deg_colまたはその他を直接使用する場合、ユーザーはレンダリング中に画面上に指を描くことでそれらを変更できます。 これらのマイクロ秒のレンダリングでは、変更が重要でないことは明らかです。 それでも機能する

 c.rotate(deg_col, cx, cy);
      
      





そして

 c.rotate(-deg_col, cx, cy);
      
      







キャンバスを異なる量だけ回転させます。 そして、この違いは徐々に蓄積されます。



もちろん、ペイントのプロパティを設定することを忘れないでください。 私はこのようなものを持っています:

  private void init(Context context) { setFocusable(true); p_color.setStyle(Style.STROKE); p_satur.setStyle(Style.STROKE); p_alpha.setStyle(Style.STROKE); p_center.setStyle(Style.FILL_AND_STROKE); p_white.setStrokeWidth(2); p_white.setColor(Color.WHITE); p_white.setStyle(Style.STROKE); p_handl.setStrokeWidth(5); p_handl.setColor(Color.WHITE); p_handl.setStrokeCap(Cap.ROUND); setOnTouchListener(this); }
      
      







setFocusable(true)前回の記事ではスキップしました。



OnTouchに戻ります。



  protected void setSatScale(float f) { deg_sat = f; if (f < 90) { hsv[1] = 1; hsv[2] = f / 90; } else if (f >= 90 && f < 180) { hsv[1] = 1 - (f - 90) / 90; hsv[2] = 1; } else { hsv[1] = 0; hsv[2] = 1 - (f - 180) / 180; } mColor = Color.HSVToColor(argb[0], hsv); p_center.setColor(mColor); } protected void setAlphaScale(float f) { deg_alp = f; argb[0] = (int) (255 - f / 360 * 255); mColor = Color.HSVToColor(argb[0], hsv); alpha = (float) Color.alpha(mColor) / 255; p_center.setColor(mColor); }
      
      







まあ、どうにかして結果を取得する必要があります。 ここでも、好みの問題と特定のユースケース。 誰かがPreferenceに値を書いたり、誰かがすべての方向にIntentを送信したりする方が便利です。 実際の大人の独立したコントロールのように、Viewインターフェイスを整理することを提案します。 円の中心をクリックすることで色の値を一度送信できます。OnTouchで色が変わると、リアルタイムで送信できます。 このような散歩をして、両方を行います:



 private OnColorChangeListener listener; public interface OnColorChangeListener { public void onDismiss(int val, float alpha); public void onColorChanged(int val, float alpha); } public void setOnColorChangeListener(OnColorChangeListener l) { this.listener = l; }
      
      







  OnTouch: case MotionEvent.ACTION_DOWN: … … else if (c < r_centr) { listener.onDismiss(mColor, alpha); } break; case MotionEvent.ACTION_MOVE: … … listener.onColorChanged(mColor, alpha); break; } return true; }
      
      







何も忘れないでね そうそう。 現在の色の値をColorPickerに渡すことをお勧めします。 追加:



  public void setUsedColor(int color, float a) { mColor = color; Color.colorToHSV(mColor, hsv); setColScale(hsv[0]); float deg = 0; if (hsv[1] == 1) deg = 90 * hsv[2]; else if (hsv[2] == 1) deg = 180 - 90 * hsv[1]; else if (hsv[1] == 0) deg = 360 - 180 * hsv[2]; setSatScale(deg); setAlphaScale(360 - 360 * a); }
      
      







PS:実際の使用でもう1つのニュアンスが見つかりました。 結果の色を(ColorFilterの形式で)写真に適用しようとしても、透明度は変わりません。 それとも何か不足していますか? もしそうなら、より経験豊富な仲間が私を修正することを願っています。 以前にColor.alpha(mColor)メソッドを使用して透明度値を取得していたsetAlphaメソッドを使用する必要がありました。 intの値は0〜255であり、setAlpha(int)は最近廃止されました。 0〜1のフロートが必要です(setAlphaタイプ((float)Color.alpha(mColor)/ 255));



コントロールの普遍性を主張しているので、これらの計算を入れることは理にかなっています。 また、透明度のフォーマットを0〜1に設定します。 インターフェイスで別のメソッドを使用できます。色に加えて2番目のパラメーターを使用できます-好みの問題です。 これをコードに追加しました。



完全な汎用性のために、すべてのコンポーネントを個別に発行することができます-必要な場所がわかりません。 私は今それを理解していません、これは急須であっても問題ではないと思います。



これですべてです。



All Articles