Ampliación de la clase de Android View para agregar un dropshadow

Quiero extender LinearLayout para que cuando mi diseño se dibuja una gota de sombra se añade por debajo de él. He jugado alrededor de sobrepasar el método onDraw , pero estoy un poco perdido. Cualquier ayuda con esto o incluso sugerencias de la biblioteca sería muy apreciada!

He aquí un ejemplo de la vista de sombra que estoy tratando de lograr. No creo que pueda usar un parche nueve aquí porque necesito que el contenido de la vista esté dentro de la caja blanca. Esto significaría que tendría que saber la distancia entre la frontera y el final de la PNG. Sin embargo, creo que diferentes densidades de pantalla significan que esta distancia será siempre la misma PX pero no la misma DP.

Por lo tanto, para ser claro, necesito una forma de extender la clase View para que una sombra se dibuje debajo de ella cuando se agrega a un diseño. No hay soluciones XML o 9Patch por favor.

Introduzca aquí la descripción de la imagen

Gracias

Jack

Estoy de acuerdo con los comentarios sobre tu pregunta: el efecto dropshadow programático es una mala elección, y puedes lograr el mismo efecto con un simple 9patch (o un conjunto de ellos) como se indica aquí .

BTW era demasiado curioso, y terminé con hackear una solución después del trabajo.

El código presentado es una prueba, y debe ser concebido como una simple prueba de concepto (así que por favor, no downvote). Algunas de las operaciones que se muestran son bastante caras , y pueden afectar seriamente las actuaciones. (Hay muchos ejemplos alrededor, mire aquí , aquí para tener una idea). Debe ser una solución de último recurso sólo para un componente que se muestra una vez en uno.

 public class BalloonView extends TextView { protected NinePatchDrawable bg; protected Paint paint; protected Rect padding = new Rect(); protected Bitmap bmp; public BalloonView(Context context) { super(context); init(); } public BalloonView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public BalloonView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } @SuppressLint("NewApi") protected void init() { // decode the 9patch drawable bg = (NinePatchDrawable) getResources().getDrawable(R.drawable.balloon); // get paddings from the 9patch and apply them to the View bg.getPadding(padding); setPadding(padding.left, padding.top, padding.right, padding.bottom); // prepare the Paint to use below paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.rgb(255,255,255)); paint.setStyle(Style.FILL); // this check is needed in order to get this code // working if target SDK>=11 if( Build.VERSION.SDK_INT >= 11 ) setLayerType(View.LAYER_TYPE_SOFTWARE, paint); // set the shadowLayer paint.setShadowLayer( padding.left * .2f, // radius 0f, // blurX padding.left * .1f, // blurY Color.argb(128, 0, 0, 0) // shadow color ); } @Override protected void onDraw(Canvas canvas) { int w = getMeasuredWidth(); int h = getMeasuredHeight(); // set 9patch bounds according to view measurement // NOTE: if not set, the drawable will not be drawn bg.setBounds(0, 0, w, h); // this code looks expensive: let's do once if( bmp == null ) { // it seems like shadowLayer doesn't take into account // alpha channel in ARGB_8888 sources... bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888); // draw the given 9patch on the brand new bitmap Canvas tmp = new Canvas(bmp); bg.draw(tmp); // extract only the alpha channel bmp = bmp.extractAlpha(); } // this "alpha mask" has the same shape of the starting 9patch, // but filled in white and **with the dropshadow**!!!! canvas.drawBitmap(bmp, 0, 0, paint); // let's paint the 9patch over... bg.draw(canvas); super.onDraw(canvas); } } 

En primer lugar para conseguir la sombra programática de la gota usted tiene que ocuparse de Paint.setShadowLayer(...) como indicado aquí . Básicamente, debe definir una capa de sombra para el objeto Paint que se utiliza para dibujar en el Canvas de su vista personalizada. Desafortunadamente no puedes usar un objeto Paint para dibujar un NinePatchDrawable, así que necesitas convertirlo en un Bitmap (1st hack). Además, parece que las capas de sombra no pueden funcionar correctamente con las imágenes ARGB_8888, por lo que la única manera que encontré para obtener una sombra adecuada ha sido dibujar la máscara alfa del NinePatchDrawable dado (segundo hack) justo debajo de sí mismo.

Aquí hay un par de sshots (probado en Android 2.3.3@mdpi y 4.2.2@xhdpi) Introduzca aquí la descripción de la imagenIntroduzca aquí la descripción de la imagen

Edit: sólo para ser minucioso, adjunto el 9patch utilizado en la prueba (colocado en res/drawable/mdpi ) Introduzca aquí la descripción de la imagen

Pruebe esta técnica.

Container_dropshadow.xml

  <!-- Drop Shadow Stack --> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#00CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#10CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#20CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#30CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#50CCCCCC" /> </shape> </item> <!-- Background --> <item> <shape> <solid android:color="@color/white" /> <corners android:radius="3dp" /> </shape> </item> 

A continuación, puede aplicarlo a un diseño XML como fondo, como

LinearLayout android: background = "@ drawable / container_dropshadow"

Esta es la forma más simple de dejar caer la sombra a cualquier cosa ya sea de diseño, botón, etc background.xml

  <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item > <shape android:shape="rectangle"> <solid android:color="@android:color/darker_gray" /> <corners android:radius="5dp"/> </shape> </item> <item android:right="1dp" android:left="1dp" android:bottom="2dp"> <shape android:shape="rectangle"> <solid android:color="@android:color/white"/> <corners android:radius="5dp"/> </shape> </item> </layer-list> 

En tu main.xml

 <LineaLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/background" /> 
  • Presentar contenido html como "páginas dinámicas"
  • Cómo crear un ImageView que llena la altura de los padres y muestra una imagen lo más grande posible?
  • Cómo convertir linearlayout a imagen
  • SurfaceView con vista previa de cámara no se destruye
  • Cómo puede utilizar valores de cadena de preferencias compartidas en la clase de vista de superficie en Android
  • OnDraw Vista personalizada dentro de un Scrollview
  • Cómo obtener la vista en la lista de vista ampliable en mi caso no muestran la lista ampliable que muestra en blanco
  • Cómo crear un grupo de vistas personalizado en android con el ejemplo
  • ¿Android View.postDelayed referencia de la fuga?
  • Método recomendado para presentar texto con formato en Android?
  • Cómo obtener la vista del grupo en la lista expandiblelist en android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.