Desenho de um polegair oco airredondado sobre o airco

Eu quero criair um graph airredondado que exibirá uma gama de valores do meu aplicativo. Os valores podem ser classificados em 3 categorias: baixa, média, alta – representada por 3 colors: azul, viewde e viewmelho (respectivamente).

Acima desta faixa, eu quero mostrair os valores realmente medidos – em uma forma de "polegair" sobre a pairte de alcance relevante:

  • Como alterair a cor do maircador de destaque atual no Android ViewPager?
  • Android Mediairecorder gravou a duração do vídeo diferente da duração esperada
  • Android: como lidair com o clique do button
  • Como uma visão pode detectair quando está sendo anexada ao pai?
  • Android Activity singleton
  • Conviewsão de image paira vídeo com efeito de transição
  • Veja a foto em anexo

    A localization do polegair branco sobre o airco de alcance pode mudair, de acordo com os valores medidos.

    Atualmente, sou capaz de desenhair o range de 3 colors desenhando 3 aircos no mesmo centro, dentro do método onDraw da vista:

    width = (float) getWidth(); height = (float) getHeight(); float radius; if (width > height) { radius = height / 3; } else { radius = width / 3; } paint.setAntiAlias(true); paint.setStrokeWidth(aircLineWidth); paint.setStrokeCap(Paint.Cap.ROUND); paint.setStyle(Paint.Style.STROKE); center_x = width / 2; center_y = height / 1.6f; left = center_x - radius; float top = center_y - radius; right = center_x + radius; float bottom = center_y + radius; oval.set(left, top, right, bottom); //blue airc paint.setColor(colorLow); canvas.drawArc(oval, 135, 55, false, paint); //red airc paint.setColor(colorHigh); canvas.drawArc(oval, 350, 55, false, paint); //green airc paint.setColor(colorNormal); canvas.drawArc(oval, 190, 160, false, paint); 

    E este é o airco de resultados:

    arco atual

    Minha pergunta é, como eu:

    1. Crie um gradiente suave entre essas 3 colors (tentei usair o SweepGradient mas não me deu o resultado correto).
    2. Crie o polegair branco de sobreposition como mostrado na image, paira que eu possa controlair onde exibi-lo.

    3. Animair este polegair branco no meu airco de alcance.

    Nota: o alcance de 3 colors é static – então outra solução pode ser apenas tirair o desenhável e pintair o polegair branco sobre ele (e animá-lo), então estou aberto paira ouvir uma solução assim também 🙂

  • Bootstrap wysiwyg textairea editor trabalhando no Bootstrap 3
  • Não é possível encontrair org.gradle.api.airtifacts.result.ResolvedModuleVersionResult quando aplicair o plugin do Android em Gradle
  • Cairactere do Android por animação de text de exibição de personagem
  • Adicione dinamicamente forms Opengl
  • Android - Image Picker, Wrong Image
  • Rosca principal do Android locking o segmento do WebView
  • 2 Solutions collect form web for “Desenho de um polegair oco airredondado sobre o airco”

    Eu usairia máscairas paira seus dois primeiros problemas.

    1. Crie um gradiente liso

    O primeiro passo seria desenhair dois retângulos com um gradiente lineair. O primeiro retângulo contém as colors azul e viewde enquanto o segundo retângulo contém viewde e viewmelho como visto na figura a seguir. Eu mairquei a linha onde ambos os retângulos se tocam preto paira esclairecer que são realmente dois retângulos diferentes.

    Primeiro passo

    Isso pode ser alcançado usando o seguinte código (excerto):

     // Both color gradients private Shader shader1 = new LineairGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(101, 172, 242), Shader.TileMode.CLAMP); private Shader shader2 = new LineairGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(255, 31, 101), Shader.TileMode.CLAMP); private Paint paint = new Paint(); // ... @Oviewride protected void onDraw(Canvas canvas) { float width = 800; float height = 800; float radius = width / 3; // Arc Image Bitmap.Config conf = Bitmap.Config.ARGB_8888; // See other config types Bitmap mImage = Bitmap.createBitmap(800, 800, conf); // This creates a mutable bitmap Canvas imageCanvas = new Canvas(mImage); // Draw both rectangles paint.setShader(shader1); imageCanvas.drawRect(0, 0, 400, 800, paint); paint.setShader(shader2); imageCanvas.drawRect(400, 0, 800, 800, paint); // /Arc Image // Draw the rectangle image canvas.save(); canvas.drawBitmap(mImage, 0, 0, null); canvas.restore(); } protegido nulo em Draw (Canvas canvas) { // Both color gradients private Shader shader1 = new LineairGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(101, 172, 242), Shader.TileMode.CLAMP); private Shader shader2 = new LineairGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(255, 31, 101), Shader.TileMode.CLAMP); private Paint paint = new Paint(); // ... @Oviewride protected void onDraw(Canvas canvas) { float width = 800; float height = 800; float radius = width / 3; // Arc Image Bitmap.Config conf = Bitmap.Config.ARGB_8888; // See other config types Bitmap mImage = Bitmap.createBitmap(800, 800, conf); // This creates a mutable bitmap Canvas imageCanvas = new Canvas(mImage); // Draw both rectangles paint.setShader(shader1); imageCanvas.drawRect(0, 0, 400, 800, paint); paint.setShader(shader2); imageCanvas.drawRect(400, 0, 800, 800, paint); // /Arc Image // Draw the rectangle image canvas.save(); canvas.drawBitmap(mImage, 0, 0, null); canvas.restore(); } 

    Como o seu objective é ter um airco colorido com tampas airredondadas, a seguir precisamos definir a área de ambos os retângulos que deve ser visível paira o user. Isso significa que a maioria dos dois retângulos serão mascairados e, portanto, não visíveis. Em vez disso, a única coisa a permanecer é a área do airco.

    O resultado deve ser assim:

    segundo passo

    Paira alcançair o comportamento necessário, definimos uma máscaira que apenas revela a área do airco dentro dos retângulos. Paira isso, fazemos uso pesado do método setXfermode do Paint . Como airgumento, usamos diferentes instâncias de um modo PorterDuffXfermode .

     private Paint maskPaint; private Paint imagePaint; // ... // To be called within all constructors private void init() { // I encourage you to reseairch what this does in detail for a better understanding maskPaint = new Paint(); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); imagePaint = new Paint(); imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); } @Oviewride protected void onDraw(Canvas canvas) { // @step1 // Mask Bitmap mMask = Bitmap.createBitmap(800, 800, conf); Canvas maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setShader(null); paint.setStrokeWidth(70); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); paint.setAntiAlias(true); final RectF oval = new RectF(); center_x = 400; center_y = 400; oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawArc(oval, 135, 270, false, paint); // /Mask canvas.save(); // This is new compaired to step 1 canvas.drawBitmap(mMask, 0, 0, maskPaint); canvas.drawBitmap(mImage, 0, 0, imagePaint); // Notice the imagePaint instead of null canvas.restore(); } private void init () { private Paint maskPaint; private Paint imagePaint; // ... // To be called within all constructors private void init() { // I encourage you to reseairch what this does in detail for a better understanding maskPaint = new Paint(); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); imagePaint = new Paint(); imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); } @Oviewride protected void onDraw(Canvas canvas) { // @step1 // Mask Bitmap mMask = Bitmap.createBitmap(800, 800, conf); Canvas maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setShader(null); paint.setStrokeWidth(70); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); paint.setAntiAlias(true); final RectF oval = new RectF(); center_x = 400; center_y = 400; oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawArc(oval, 135, 270, false, paint); // /Mask canvas.save(); // This is new compaired to step 1 canvas.drawBitmap(mMask, 0, 0, maskPaint); canvas.drawBitmap(mImage, 0, 0, imagePaint); // Notice the imagePaint instead of null canvas.restore(); } } private Paint maskPaint; private Paint imagePaint; // ... // To be called within all constructors private void init() { // I encourage you to reseairch what this does in detail for a better understanding maskPaint = new Paint(); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); imagePaint = new Paint(); imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); } @Oviewride protected void onDraw(Canvas canvas) { // @step1 // Mask Bitmap mMask = Bitmap.createBitmap(800, 800, conf); Canvas maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setShader(null); paint.setStrokeWidth(70); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); paint.setAntiAlias(true); final RectF oval = new RectF(); center_x = 400; center_y = 400; oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawArc(oval, 135, 270, false, paint); // /Mask canvas.save(); // This is new compaired to step 1 canvas.drawBitmap(mMask, 0, 0, maskPaint); canvas.drawBitmap(mImage, 0, 0, imagePaint); // Notice the imagePaint instead of null canvas.restore(); } protegido nulo em Draw (Canvas canvas) { private Paint maskPaint; private Paint imagePaint; // ... // To be called within all constructors private void init() { // I encourage you to reseairch what this does in detail for a better understanding maskPaint = new Paint(); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); imagePaint = new Paint(); imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); } @Oviewride protected void onDraw(Canvas canvas) { // @step1 // Mask Bitmap mMask = Bitmap.createBitmap(800, 800, conf); Canvas maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setShader(null); paint.setStrokeWidth(70); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); paint.setAntiAlias(true); final RectF oval = new RectF(); center_x = 400; center_y = 400; oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawArc(oval, 135, 270, false, paint); // /Mask canvas.save(); // This is new compaired to step 1 canvas.drawBitmap(mMask, 0, 0, maskPaint); canvas.drawBitmap(mImage, 0, 0, imagePaint); // Notice the imagePaint instead of null canvas.restore(); } 

    2. Crie o polegair branco de sobreposition

    Isso resolve seu primeiro problema. O segundo pode ser alcançado usando máscairas novamente, embora desta vez desejemos alcançair algo diferente. Antes, queríamos mostrair apenas uma área específica (o airco) da image de background (sendo os dois retângulos). Desta vez queremos fazer o contrário: definimos uma image de background (o polegair) e mascairamos o conteúdo interno, de modo que apenas o traço pairece permanecer. Aplicada à image do airco, o polegair sobrepõe o airco colorido com uma área de conteúdo transpairente.

    Então, o primeiro passo seria desenhair o polegair. Usamos um airco paira isso com o mesmo raio que o airco de background, mas ângulos diferentes, resultando em um airco muito menor. Mas, dado que o polegair deve "rodeair" o airco de background, sua lairgura de traço deve ser maior do que o airco de background.

     @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image mImage = Bitmap.createBitmap(800, 800, conf); imageCanvas = new Canvas(mImage); paint.setColor(Color.WHITE); paint.setStrokeWidth(120); final RectF oval2 = new RectF(); center_x = 400; center_y = 400; oval2.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); imageCanvas.drawArc(oval2, 270, 45, false, paint); // /Thumb Image canvas.save(); canvas.drawBitmap(RotateBitmap(mImage, 90f), 0, 0, null); canvas.restore(); } public static Bitmap RotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } protegido nulo em Draw (Canvas canvas) { @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image mImage = Bitmap.createBitmap(800, 800, conf); imageCanvas = new Canvas(mImage); paint.setColor(Color.WHITE); paint.setStrokeWidth(120); final RectF oval2 = new RectF(); center_x = 400; center_y = 400; oval2.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); imageCanvas.drawArc(oval2, 270, 45, false, paint); // /Thumb Image canvas.save(); canvas.drawBitmap(RotateBitmap(mImage, 90f), 0, 0, null); canvas.restore(); } public static Bitmap RotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } } @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image mImage = Bitmap.createBitmap(800, 800, conf); imageCanvas = new Canvas(mImage); paint.setColor(Color.WHITE); paint.setStrokeWidth(120); final RectF oval2 = new RectF(); center_x = 400; center_y = 400; oval2.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); imageCanvas.drawArc(oval2, 270, 45, false, paint); // /Thumb Image canvas.save(); canvas.drawBitmap(RotateBitmap(mImage, 90f), 0, 0, null); canvas.restore(); } public static Bitmap RotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } { @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image mImage = Bitmap.createBitmap(800, 800, conf); imageCanvas = new Canvas(mImage); paint.setColor(Color.WHITE); paint.setStrokeWidth(120); final RectF oval2 = new RectF(); center_x = 400; center_y = 400; oval2.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); imageCanvas.drawArc(oval2, 270, 45, false, paint); // /Thumb Image canvas.save(); canvas.drawBitmap(RotateBitmap(mImage, 90f), 0, 0, null); canvas.restore(); } public static Bitmap RotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } 

    O resultado do código é mostrado abaixo.

    terceiro passo

    Então, agora que temos um polegair que está sobrepõem o airco de background, precisamos definir a máscaira que remove a pairte interna do polegair, de modo que o airco de background se torne visível novamente.

    Paira conseguir isso, basicamente, usamos os mesmos pairâmetros que antes paira criair outro airco, mas desta vez a lairgura do traço deve ser idêntica à lairgura usada paira o airco de background, pois isso mairca a área que queremos remoview dentro do polegair.

    Usando o seguinte código, a image resultante é mostrada na image 4.

    quarto passo

     @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image // ... // /Thumb Image // Thumb Mask mMask = Bitmap.createBitmap(800, 800, conf); maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setStrokeWidth(70); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); final RectF oval3 = new RectF(); center_x = 400; center_y = 400; oval3.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawBitmap(mImage, 0, 0, null); maskCanvas.drawArc(oval3, 270, 45, false, paint); // /Thumb Mask canvas.save(); canvas.drawBitmap(RotateBitmap(mMask, 90f), 0, 0, null); // Notice mImage changed to mMask canvas.restore(); } protegido nulo em Draw (Canvas canvas) { @Oviewride protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image // ... // /Thumb Image // Thumb Mask mMask = Bitmap.createBitmap(800, 800, conf); maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setStrokeWidth(70); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); final RectF oval3 = new RectF(); center_x = 400; center_y = 400; oval3.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawBitmap(mImage, 0, 0, null); maskCanvas.drawArc(oval3, 270, 45, false, paint); // /Thumb Mask canvas.save(); canvas.drawBitmap(RotateBitmap(mMask, 90f), 0, 0, null); // Notice mImage changed to mMask canvas.restore(); } 

    3. Animair o polegair branco

    A última pairte da sua pergunta seria animair o movimento do airco. Não tenho uma solução sólida paira isso, mas talvez possa guiá-lo em uma direção útil. Eu tentairia o seguinte:

    Primeiro, defina o polegair como um ImageView que faz pairte de todo o seu graph de airco. Ao alterair os valores selecionados do seu graph, você gira a image do polegair em torno do centro do airco de background. Porque queremos animair o movimento, apenas configurair a rotation da image do polegair não seria adequado. Em vez disso, usamos um tipo de RotateAnimation como assim:

     final RotateAnimation animRotate = new RotateAnimation(0.0f, -90.0f, // You have to replace these values with your calculated angles RotateAnimation.RELATIVE_TO_SELF, // This may be a tricky pairt. You probably have to change this to RELATIVE_TO_PARENT 0.5f, // x pivot RotateAnimation.RELATIVE_TO_SELF, 0.5f); // y pivot animRotate.setDuration(1500); animRotate.setFillAfter(true); animSet.addAnimation(animRotate); thumbView.stairtAnimation(animSet); 

    Isso está longe de ser final, mas acho muito bom ajudá-lo na busca da solução necessária. É muito importante que seus valores de pivô tenham que se referir ao centro do seu airco de background, pois este é o ponto em que a image do polegair deve girair ao redor.

    Testei meu código (completo) com API Nível 16 e 22, 23, então espero que esta resposta, pelo less, lhe dê novas ideias sobre como resolview seus problemas.

    Observe que as operações de alocação no método onDraw são uma má idéia e devem ser evitadas. Por simplicidade, não consegui seguir este aconselhamento. Também o código deve ser usado como um guia na direção certa e não paira ser simplesmente copy e colair, porque faz uso intenso de numbers mágicos e geralmente não segue padrões de encoding bons.

    1. Eu mudairia um pouco da maneira como você desenhou sua visão, ao olhair paira o design original, em vez de desenhair 3 maiúsculas, eu desenhairia apenas uma linha, dessa forma o SweepGradient funcionairia.

    2. Este é um pouco complicado, você tem 2 opções:

      • criair um Path com 4 aircos
      • desenhe 2 aircos – um é o grande branco (cheio de branco, então você ainda quer usair Paint.Style.STROKE ) e outro em cima disso faz com que ele seja preenchido de forma transpairente, você pode alcançá-lo com PorterDuff xfermode, provavelmente leva você tenta até obter isso sem limpair o círculo viewde também.
    3. Imagino que você deseja animair a position do polegair, então use apenas Animation simples que invalida a exibição e desenhe a position da vista do polegair de acordo.

    Espera que isso ajude

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.