56548

Memory heavy oval gradient

Question:

As you may know it is not possible to draw an oval radial gradient using regular Android API.

This is what I want to achieve:

<a href="https://i.stack.imgur.com/rNGjO.png" rel="nofollow"><img alt="Expected effect" class="b-lazy" data-src="https://i.stack.imgur.com/rNGjO.png" data-original="https://i.stack.imgur.com/rNGjO.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

So I implemented this solution: draw a regular radial gradient on a square bitmap and then this bitmap will get stretched by the view itself (idea found here: <a href="https://stackoverflow.com/a/3543899/649910" rel="nofollow">https://stackoverflow.com/a/3543899/649910</a>)

This works great however this solution takes a lot of memory, because of BitmapDrawable usage (see implementation details below).

Any ideas on how to avoid usage of such a big bitmap are welcome!

This my code:

public class OvalGradientView extends ImageView { private Drawable defaultBackgroundDrawable; public OvalGradientView(Context context) { super(context); init(); } public OvalGradientView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public OvalGradientView(Context context, AttributeSet attrs, int defStyleAttr, Paint paint) { super(context, attrs, defStyleAttr); init(); } private void init() { setScaleType(ScaleType.FIT_XY); defaultBackgroundDrawable = getResources().getDrawable(R.drawable.default_background); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int width = getWidth(); int height = getHeight(); Rect currentBounds = defaultBackgroundDrawable.getBounds(); // check if we already have bitmap for these bounds if (currentBounds.right == width && currentBounds.bottom == height) { return; } // draw the drawable on square bitmap, it will be then stretched if needed to rectangular shape // as the view gets more rectangular defaultBackgroundDrawable.setBounds(0, 0, width, width); Bitmap defaultBackgroundBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(defaultBackgroundBitmap); defaultBackgroundDrawable.draw(canvas); setImageBitmap(defaultBackgroundBitmap); } }

And this is the drawable XML - default_background

<shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#ffffff" android:endColor="#ff6600" android:gradientRadius="50%p" android:type="radial" /> </shape

Answer1:

I wouldn't trust my own ability to create bitmaps like that, especially if they are full screen. Why not apply the xml shape as a background to the container view in xml as well? It will stretch to the proportions of the view if the width and height are match_parent

public class OvalGradientView extends ImageView { public OvalGradientView(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.my_sexy_gradient, this, true); } }

my_sexy_gradient.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/default_background"/>

Answer2:

I ended up with this implementation:

public class MyBackgroundView extends ImageView { public MyBackgroundView(Context context) { super(context); } public MyBackgroundView(Context context, AttributeSet attrs) { super(context, attrs); } public MyBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } { setBackgroundResource(R.drawable.my_background); setScaleType(ScaleType.FIT_XY); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (!changed) { return; } int width = right - left; int height = bottom - top; float aspectRatio = (float) width / height; if (aspectRatio > 1f) { setScaleX(aspectRatio); } else { setScaleY(1 / aspectRatio); } } }

where my_background is:

<shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="@color/my_background_start_color" android:endColor="@color/my_background_end_color" android:gradientRadius="@fraction/my_background_gradient_radius_percent" android:type="radial" /> </shape>

Width and height of this view are both match_parent.

Recommend

  • Camera Intent return null only on some devices
  • How can I make curly edges on an imageview on android?
  • Custom ImageView class onClick change imageResource
  • Android View resize and WindowManager: unwanted transition during child view placement
  • 'outofmemoryerror' in the getView() from custom BaseAdapter
  • How to do Gallery Images swap Left To right bydefault
  • ImageSwitcher is not showing outAnimation
  • How to preview images from the gallery in the correct way?
  • ClickableSpan not clickable in custom view (not TextView)
  • Collapsible Toolbar - Make Fragment Footer Always Visible in Android
  • Why this orion subscription don't works as I want?
  • grails access controller from taglib
  • Draw smooth line in InkCanvas WPF with Kinect
  • Display informations about a bubble chart D3.js in AngularJS
  • How can i create a keyboard listener in Android?
  • Add multiple images and text to each ViewPager slide
  • AngularJS: minifications breaks my directive
  • Change status / notification bar color on api below 21 android?
  • Android device not shown with adb
  • looking for a slight variant of GROUP BY
  • Orion does not notify Cygnus (timeout error)
  • How to change size of QPixmap?
  • How to move move a rectangle in JFrame using KeyListener?
  • Android MapView parts of map missing
  • Android gradle : Error No resource found that matches the given name: attr when refer to an android
  • Compiling Element Causes Input Caret Position to Move to End
  • AngularJS : transclude ng-repeat inside directive
  • How to apply async task into this
  • How to get a android ListView item selector to use state_pressed
  • Circle movement upon rectangle Collision
  • Differences between drawing an Ellipse in Android and Java
  • Adding a new element into the DOM with angularjs does not initiate it
  • Exception in the iconization of JInternalFrame with DefaultDesktopManager
  • write text on image and show it to a imageview
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • Sorting a 2D array using the second column C++
  • failed to connect to specific WiFi in android programmatically
  • java string with new operator and a literal
  • How can I use threading to 'tick' a timer to be accessed by other threads?