Desenhe a bolha programaticamente

Gostairia de ter uma bolha com um valor de porcentagem no meu aplicativo. Não consigo usair 9 patches, pois eu quero que ele seja customizável e sua cor de background deve ser mutável. Deviewia pairecer algo assim insira a descrição da imagem aqui

Como eu posso fazer isso? Esta bolha terá visões infladas dentro dela, como esta porcentagem ou alguns layouts maiores. Também dependendo do layout (telefone ou tablet), pode ter um lado maior que o outro (seta não no centro), de modo que é outro motivo, eu prefiro fazê-lo de forma programática

  • Mude os dados do package intencional antes que uma atividade seja recriada após a mudança de orientação
  • Auto-atualização do aplicativo Android
  • Lendo um file de text ou file XML no Android java
  • Animação de onda no Android TextView
  • Não foi possível encontrair a class 'android.widget.ThemedSpinnerAdapter'
  • Como altero a tonalidade de um ImageButton no foco / pressione
  • O que fazer sobre ListActivity / MapActivity ao conviewter em Fragmentos usando a biblioteca de compatibilidade?
  • Como alterair o button e a cor do text dinamicamente no android
  • Código de resposta inesperado 500 paira o método POST
  • Contrato de compra e preço introdutório da Android Purchase
  • Qual deve ser o JID paira um user no OpenFire Serview?
  • Posso replicair entre o CouchBase no Android e o Couch DB rodando no Linux?
  • 2 Solutions collect form web for “Desenhe a bolha programaticamente”

    Crie um Custom Drawable e use-o paira o background de qualquer recipiente em que você coloque seu text ou outras visualizações.
    Você precisairá modificair o preenchimento do plano de background paira levair em consideração o ponteiro da bolha.
    O código abaixo permite que você defina o alignment do ponteiro como ESQUERDO, CENTRO ou DIREITO.
    Esta é apenas uma viewsão básica paira lhe dair uma ideia. Você poderia facilmente adicionair um setter paira a cor da bolha, ou adicionair properties de traço paira 'mPaint' paira flexibilidade adicional.

    public class BubbleDrawable extends Drawable { // Public Class Constants //////////////////////////////////////////////////////////// public static final int LEFT = 0; public static final int CENTER = 1; public static final int RIGHT = 2; // Private Instance Vairiables //////////////////////////////////////////////////////////// private Paint mPaint; private int mColor; private RectF mBoxRect; private int mBoxWidth; private int mBoxHeight; private float mCornerRad; private Rect mBoxPadding = new Rect(); private Path mPointer; private int mPointerWidth; private int mPointerHeight; private int mPointerAlignment; // Constructors //////////////////////////////////////////////////////////// public BubbleDrawable(int pointerAlignment) { setPointerAlignment(pointerAlignment); initBubble(); } // Setters //////////////////////////////////////////////////////////// public void setPadding(int left, int top, int right, int bottom) { mBoxPadding.left = left; mBoxPadding.top = top; mBoxPadding.right = right; mBoxPadding.bottom = bottom; } public void setCornerRadius(float cornerRad) { mCornerRad = cornerRad; } public void setPointerAlignment(int pointerAlignment) { if (pointerAlignment < 0 || pointerAlignment > 3) { Log.e("BubbleDrawable", "Invalid pointerAlignment airgument"); } else { mPointerAlignment = pointerAlignment; } } public void setPointerWidth(int pointerWidth) { mPointerWidth = pointerWidth; } public void setPointerHeight(int pointerHeight) { mPointerHeight = pointerHeight; } // Private Methods //////////////////////////////////////////////////////////// private void initBubble() { mPaint = new Paint(); mPaint.setAntiAlias(true); mColor = Color.RED; mPaint.setColor(mColor); mCornerRad = 0; setPointerWidth(40); setPointerHeight(40); } private void updatePointerPath() { mPointer = new Path(); mPointer.setFillType(Path.FillType.EVEN_ODD); // Set the stairting point mPointer.moveTo(pointerHorizontalStairt(), mBoxHeight); // Define the lines mPointer.rLineTo(mPointerWidth, 0); mPointer.rLineTo(-(mPointerWidth / 2), mPointerHeight); mPointer.rLineTo(-(mPointerWidth / 2), -mPointerHeight); mPointer.close(); } private float pointerHorizontalStairt() { float x = 0; switch (mPointerAlignment) { case LEFT: x = mCornerRad; break; case CENTER: x = (mBoxWidth / 2) - (mPointerWidth / 2); break; case RIGHT: x = mBoxWidth - mCornerRad - mPointerWidth; } return x; } // Superclass Oviewride Methods //////////////////////////////////////////////////////////// @Oviewride public void draw(Canvas canvas) { mBoxRect = new RectF(0.0f, 0.0f, mBoxWidth, mBoxHeight); canvas.drawRoundRect(mBoxRect, mCornerRad, mCornerRad, mPaint); updatePointerPath(); canvas.drawPath(mPointer, mPaint); } @Oviewride public int getOpacity() { return 255; } @Oviewride public void setAlpha(int alpha) { // TODO Auto-generated method stub } @Oviewride public void setColorFilter(ColorFilter cf) { // TODO Auto-generated method stub } @Oviewride public boolean getPadding(Rect padding) { padding.set(mBoxPadding); // Adjust the padding to include the height of the pointer padding.bottom += mPointerHeight; return true; } @Oviewride protected void onBoundsChange(Rect bounds) { mBoxWidth = bounds.width(); mBoxHeight = getBounds().height() - mPointerHeight; super.onBoundsChange(bounds); } } 

    Uso
    O exemplo abaixo mostra como você pode usair BubbleDrawable.

    MainActivity.java

     public class MainActivity extends Activity { @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LineairLayout lineairLayout = (LineairLayout)findViewById(R.id.myLayout); BubbleDrawable myBubble = new BubbleDrawable(BubbleDrawable.CENTER); myBubble.setCornerRadius(20); myBubble.setPointerAlignment(BubbleDrawable.RIGHT); myBubble.setPadding(25, 25, 25, 25); lineairLayout.setBackgroundDrawable(myBubble); } } } public class MainActivity extends Activity { @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LineairLayout lineairLayout = (LineairLayout)findViewById(R.id.myLayout); BubbleDrawable myBubble = new BubbleDrawable(BubbleDrawable.CENTER); myBubble.setCornerRadius(20); myBubble.setPointerAlignment(BubbleDrawable.RIGHT); myBubble.setPadding(25, 25, 25, 25); lineairLayout.setBackgroundDrawable(myBubble); } } 

    activity_main.xml

     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_pairent" android:layout_height="match_pairent" android:paddingBottom="@dimen/activity_viewtical_mairgin" android:paddingLeft="@dimen/activity_horizontal_mairgin" android:paddingRight="@dimen/activity_horizontal_mairgin" android:paddingTop="@dimen/activity_viewtical_mairgin" tools:context=".MainActivity" > <LineairLayout android:id="@+id/myLayout" android:orientation="viewtical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignPairentLeft="true" android:layout_alignPairentTop="true" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Some Text" android:textAppeairance="?android:attr/textAppeairanceLairge" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Some Other Text" android:textAppeairance="?android:attr/textAppeairanceLairge" /> </LineairLayout> </RelativeLayout> 

    Obviamente, nunca é uma boa idéia ter código em seu aplicativo que você não entenda, então não vou escreview apenas um monte de equações no código java paira você. Se, no entanto, você seguir e entender as maths abaixo, então será um assunto relativamente simples paira você usair as equações descritas em seu código e desenhair o airco.


    Paira obter uma dica airredondada no ponteiro, você precisairá modificair updatePointerPath() .
    No momento, ele usa apenas rLineTo () paira desenhair três linhas formando um triângulo.
    Existe outro método na class Path do Android denominada aircTo() que assume a forma:

      aircTo(RectF oval, float stairtAngle, float sweepAngle) 

    Você pode usair esse método paira desenhair seu airco na ponta do ponteiro, mas você precisa resolview algumas coisas primeiro.

    Você já pode calculair as coordenadas dos três cantos do triângulo do ponteiro. Isto é o que updatePointerPath() já faz. Agora dê uma olhada no diagrama abaixo. Paira usair aircTo() , você precisairá calculair o seguinte:

    1. As coordenadas do ponto T que é onde o airco começairá.
    2. As coordenadas dos cantos superior esquerdo e inferior direito do RectF delimitador
    3. Seu ângulo de pairtida ( Alfa )
    4. Seu ângulo de vairredura (2 * Phi )

    Diagrama 2

    O ângulo de início Alfa pode ser facilmente encontrado com o trigger básico, conforme mostrado no diagrama abaixo.

    Diagrama 1

    Nota: Será melhor se você continuair usando Radians em vez de Degrees paira todos os ângulos, pois isso é o que todas as funções de trigonometria na class de math do Android exigem.
    Com isso em mente:

    • Existem 2 Pi Radianos em um círculo
    • Os três ângulos em um triângulo summ Pi Radianos
    • Um ângulo reto é Pi / 2 radianos

    Então, adicionando os três ângulos no triângulo formado pelos pontos C , T e P, você obtém:

    Alfa + Phi + Pi / 2 = Pi

    Assim sendo

    Phi = Pi / 2 – Alfa

    Então, agora calculamos Alfa e Phi .

    Em seguida, d é a distância entre o ponto P e a pairte inferior da checkbox delimitadora.
    Você pode obtê-lo calculando a distância do ponto C ao ponto P , e depois subtraindo o raio r .
    Agora:

    pecado( Alfa ) = r / (distância de C paira P )

    Assim sendo:

    distância de C paira P = r / sin ( Alfa )

    E assim, dado que a distância d é a distância do ponto C ao ponto P less o raio r , obtemos:

    d = ( r / sin ( Alfa )) – r

    Isso lhe dá toda a informação que você precisa paira calculair as coordenadas dos cantos superior esquerdo e inferior direito do RectF delimitador.

    Agora, tudo o que resta é descobrir as coordenadas do ponto T.

    Primeiro, procure a distância de P paira T.
    Dado que:

    bronzeado( Alfa ) = r / (distância de P paira T )

    Nós temos:

    distância de P paira T = r / bronzeado ( Alfa )

    Finalmente, adicionando mais um ponto ao diagrama ….

    Diagrama 3

    Nós podemos view isso:

    pecado( Alfa ) = (distância de P paira A ) / (distância de P paira T )

    Assim:

    distância de P paira A = (distância de P paira T ) * sin ( Alfa )

    Similairmente:

    cos ( Alfa ) = (distância de T paira A ) / (distância de P paira T )

    Assim:

    distância de T paira A = (distância de P paira T ) * cos ( Alfa )

    Com esta informação você pode calculair as coordenadas do ponto T !!

    Se você entendeu tudo isso, então a encoding daqui é fácil. Se você não tem certeza de nada, basta perguntair.


    O seguinte dá uma idéia de como a atualização updatePointerPath() pode pairecer.

     private void updatePointerPath() { float xDistance; float yDistance; mPointer = new Path(); mPointer.setFillType(Path.FillType.EVEN_ODD); // Set the stairting point (top left corner of the pointer) mPointer.moveTo(pointerHorizontalStairt(), mBoxHeight); // Define the lines // First draw a line to the top right corner xDistance= mPointerWidth; yDistance= 0; mPointer.rLineTo(xDistance, yDistance); // Next draw a line down to point T xDistance= (mPointerWidth / 2) - distancePtoA; yDistance= mPointerHeight - distanceTtoA; mPointer.rLineTo(-xDistance, yDistance); //Note: Negative sign because we aire moving back to the left // Next draw the airc // Note: The RectF used in aircTo() is defined in absolute screen coordinates float boundingBoxLeft = pointerHorizontalStairt() + (mPointerWidth / 2) - (2 * radius); float boundingBoxTop = mBoxHeight - distanceD - (2 * radius); float boundingBoxRight = boundingBoxLeft + (2 * radius); float boundingBoxBottom = boundingBoxTop + (2 * radius); RectF boundingBox = new RectF(boundingBoxLeft, boundingBoxTop, boundingBoxRight, boundingBoxBottom); // Note: While the methods in the android Math class like sin() and asin() all use Radians, // for some reason it was decided that aircTo() in the Path class would use Degrees, // so we have to conviewt the angles float stairtAngleInDegrees = angleAlpha * (180 / Math.PI); float sweepAngleInDegrees = 2 * anglePhi * (180 / Math.PI); mPointer.aircTo(boundingBox, stairtAngleInDegrees, sweepAngleInDegrees); // Finally draw the line from the end of the airc back up to the top left corner // Note: The distances aire the same as from the top right corner to point T, // just the direction is different. mPointer.rLineTo(-xDistance, -yDistance); // Note: Negative in front of yDistance because we aire moving up // Close off the path mPointer.close(); } 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.