📜 ⬆️ ⬇️

The taste and color or coloring for Android

Good day again all. In this article I would like to continue the theme of custom View, namely the color selection dialog.

A small digression: Anticipating negative reviews, I want to warn in advance - the article is designed for beginners in programming. Starting to get acquainted with the development under Android, I ran into (and now I regularly come across) an interesting fact: on the Internet, a cart and a small information cart dedicated to installing and configuring Eclipse, then colorfully describe how to click New - Android Application Project and get your first HelloWord. And then immediately services - streams - binders - handlers and all sorts of other databases. In the middle is emptiness. I try to fill this emptiness, to facilitate the transition from a kettle at least to a coffee pot, so to speak. I really hope that I will help someone to find something necessary without unnecessary suffering. And I can not once again not to mention another feature of the Runet: Not so long ago, once again I stepped on a rake , I ran into a problem, one might say funny for a knowledgeable person, but unfamiliar to me. I quickly found a solution on some English-speaking forum. The topic consisted of two posts. Question and answer. Everything! If anyone is interested, I will find a link. Yes, by the way, the question that has arisen also applies to this article, so further I will mention this. So, but look at our forums - horror. Each question generates several pages of flooding on the topic “read the documentation,” but in most cases there is still no answer.

Well, sorry for the verbosity, sad, so to speak. We continue under the cut.

So, in the next project I encountered the need to change the colors of some elements in the program. That is, we need the appropriate control, let's call it ColorPicker. In the standard set such is absent, that is, each is perverted as it can. What can I say, even at Microsoft on BB there is no unity, look at the color selection dialogs in Word, say in the same Paint.
')
On a smartphone, it is not so easy to get a finger to the desired point; manually entering values ​​is also not very convenient. An Internet search, however, offers either some similarity to the aforementioned smartphone-like Paint-like dialogs, or the most simplified options for the three sliders type for RGB, a separate slider for the alpha channel, or a fixed set of several color tiles. And I don’t like to push other people's libraries into my projects, so the search was pretty quick. And I wanted everything at once. And in one place.

In the end, after long deliberation, this was born:

image

That is, everything is quite simple. The first (outer) ring represents the GRB gradient. The second in the lower half adjusts the saturation of the selected color, then turning into shades of gray. Well, the third ring is transparency. Everything is at hand at the same time. The center circle directly displays the currently selected color and in parallel serves as the OK button.

Well, now, if anyone liked this colorful monster, let's try to hook the whole thing.

Since there is not much to draw, and the rendering speed is not critical, we’ll follow the View and draw on Canvas. For the correct positioning of our arts, you need to know the dimensions, the dimensions of the View itself also want to be controlled, so we will override the onMeasure () method. It turns out here such preparation:

public class ColorPicker extends View { private float cx; private float cy; private int size; public ColorPicker(Context context) { this(context, null); } public ColorPicker(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ColorPicker(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { //   ,   -     } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mWidth = measure(widthMeasureSpec); int mHeight = measure(heightMeasureSpec); size = Math.min(mWidth, mHeight); setMeasuredDimension(size, size); //    ,    //     View       //        . //  Math.min     getConfiguration, //  size    - , //   View   .  : /*int orient = getResources().getConfiguration().orientation; switch (orient) { case Configuration.ORIENTATION_PORTRAIT: size = (int) (measureHeight * port); break; case Configuration.ORIENTATION_LANDSCAPE: size = (int) (measureHeight * land); break; }*/ calculateSizes(); //         } private int measure(int measureSpec) { int result = 0; int specMoge = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMoge == MeasureSpec.UNSPECIFIED) result = 200; else result = specSize; return result; } private void calculateSizes() { cx = size * 0.5f; cy = cx; //       . } @Override protected void onDraw(Canvas c) { super.onDraw(c); //      //   ,    –    c.drawColor(Color.BLUE); //invalidate()    } } 


Now our class must appear in the Custom & Library Views section of the element palette. Drag it to the markup of our HelloWord.

It should get something like this:

image

Happened? Great coming out.

Go to the drawing. Let's start outside. We need a ring with a gradient of colors. The ring, who does not know, is drawn like this:

  @Override protected void onDraw(Canvas c) { super.onDraw(c); c.drawCircle(cx, cy, rad_1, p_color); } 


That is, we need a radius of the circle and a brush (or paint, as there Paint is translated).
Add to our code:

 private Paint p_color = new Paint(Paint.ANTI_ALIAS_FLAG); 


  private void calculateSizes() { cx = size * 0.5f; cy = cx; //   rad_1 = size * 0.44f; // 0.44 –     .    //  : p_color.setStrokeWidth(size * 0.08f); //      0.08  size //     } 


If now to start all this, it will be like with that gopher - the ring is not visible, but it is. We just did not ask him the color. Not him, or rather, and our Paint p_color.

With color we will do the following. Remember, there are such shaders. And gradients. We define an array of four colors:
int [] mColors = new int [] {Color.RED, Color.GREEN, Color.BLUE, Color.RED};

(Of the four - so that there was no abrupt transition. From the red they started and returned to the red).
Apply a gradient to a shader, a shader to a brush, a brush to a circle, an egg in a duck, a duck in a hare ...

  Shader s = new SweepGradient(cx, cy, mColors, null); p_color.setShader(s); 


We look:

image

Pretty good, right?

But the second ring to draw is still too early. As we remember, there should be drawn a gradient of saturation of the selected color. Nothing has been selected yet. We must make our View respond to the extremities of the user. That is, use the OnTouch method. And in order for our class to be completely self-sufficient, we will depict OnTouch directly inside the class:

 //      init()  setOnTouchListener(this); //  ,     public class ColorPicker extends View implements OnTouchListener 


Then Eclipse thoughtfully suggests adding a method:

 @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { //   ,    case MotionEvent.ACTION_DOWN: //      -       break; case MotionEvent.ACTION_MOVE: //       break; } invalidate(); return true; } 


It seems everything is simple, but here came the very rake mentioned at the beginning of the article. Eclipse stubbornly demanded something. As it turned out, he wanted to add onTouch:

  case MotionEvent.ACTION_UP: v.performClick(); break; 


And accordingly the method:

  @Override public boolean performClick() { return super.performClick(); } 


After that, everyone calmed down. Now we boldly get the coordinates in onTouch:

  case MotionEvent.ACTION_DOWN: float a = Math.abs(event.getX() - cx); float b = Math.abs(event.getY() - cy); break; case MotionEvent.ACTION_MOVE: float x = event.getX() - cx; float y = event.getY() - cy; break; 


And go ahead - calculate colors. This is where the scope for criticism opens, because I am not on friendly terms with mathematics. Therefore, I propose to continue in the next article .

Source: https://habr.com/ru/post/254797/


All Articles