(This is somewhat a follow-up on Android: How do you scale multiple views together?)
My task is to port an iPhone / iPad app on Android that consists of a simple image view on which animations are layered on top in absolute positions. While this sounds rather easy on iOS where you only have to target a few possible screen sizes, it gets rather messy with Android.
My current setup is this: A RelativeLayout in which I place my main (background) image on left = 0, top = 0 and multiple ViewFlipper instances used as "animation containers" that are positioned relatively to the upper left corner of the parent layout instance.
This approach has two basic problems:
The positioned "animations" are mis-positioned as soon as the actual size of the layout does not match the size of the main background image.
The positioned "animations" are also mis-sized, because since they usually have "enough space" around themselves, Android doesn't scale them to fit into the RelativeLayout (nor would it scale them relatively to the original background.
Since the animations itself must be interactive, its not a solution to place and position all of the animations on a transparent layer that has the same size as the main (background) image, as they'd overlap each other and only the upper-most would be interactive at all.
I thought of different solutions:
To get the the scale factor of the main image, I could retrieve its measuredWidth
and measuredHeight
and set this into relation of the original width
and height
of the view. Then I'd use this scale factor for custom positioning and eventually custom scaling. But, apparently the measuredWidth/-Height
properties are only set during the onMeasure() call and this is called after the component tree was built, so I don't know if this solution is feasible at all.
Implement my own layout manager and scale / position the views accordingly. I had a look at the implementation of RelativeLayout
, but have to admit that the onMeasure() method scares me a bit.
What would you do in my case? Is there anything I haven't yet taken into account?
Thanks in advance.
Well, answering my own question - here is the way I resolved the issue:
ImageView
with ImageView.setScaleType(ScaleType.FIT_START)
WindowManager mgr = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); mgr.getDefaultDisplay().getMetrics(metrics); Drawable image = context.getResources().getDrawable(R.drawables.someImage); float scale = metrics.widthPixels / (float) image.getIntrinsicWidth();
public class OverlayImage extends ImageView { private int imgWidth, imgHeight; private final float scale; public OverlayImage(Context context, int xPos, int yPos, float scale) { super(context); this.scale = scale; LayoutParams animParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); animParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); animParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); animParams.leftMargin = (int) (scale * xPos); animParams.topMargin = (int) (scale * yPos); setLayoutParams(animParams); Drawable dr = context.getResources().getDrawable(R.id.someImage); setBackgroundDrawable(dr); imgWidth = dr.getIntrinsicWidth(); imgHeight = dr.getIntrinsicHeight(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension((int) (scale * imgWidth), (int) (scale * imgHeight)); } }