Search code examples
androidviewaspect-ratioviewgroup

Fixed aspect ratio View


How would I go implementing a fixed aspect ratio View? I'd like to have items with 1:1 aspect ratio in a GridView. I think it's better to subclass the children than the GridView?

EDIT: I assume this needs to be done programmatically, that's no problem. Also, I don't want to limit the size, only the aspect ratio.


Solution

  • I implemented FixedAspectRatioFrameLayout, so I can reuse it and have any hosted view be with fixed aspect ratio:

    public class FixedAspectRatioFrameLayout extends FrameLayout
    {
        private int mAspectRatioWidth;
        private int mAspectRatioHeight;
    
        public FixedAspectRatioFrameLayout(Context context)
        {
            super(context);
        }
    
        public FixedAspectRatioFrameLayout(Context context, AttributeSet attrs)
        {
            super(context, attrs);
    
            init(context, attrs);
        }
    
        public FixedAspectRatioFrameLayout(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
    
            init(context, attrs);
        }
    
        private void init(Context context, AttributeSet attrs)
        {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FixedAspectRatioFrameLayout);
    
            mAspectRatioWidth = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioWidth, 4);
            mAspectRatioHeight = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioHeight, 3);
    
            a.recycle();
        }
        // **overrides**
    
        @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
        {
            int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
    
            int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
    
            int calculatedHeight = originalWidth * mAspectRatioHeight / mAspectRatioWidth;
    
            int finalWidth, finalHeight;
    
            if (calculatedHeight > originalHeight)
            {
                finalWidth = originalHeight * mAspectRatioWidth / mAspectRatioHeight; 
                finalHeight = originalHeight;
            }
            else
            {
                finalWidth = originalWidth;
                finalHeight = calculatedHeight;
            }
    
            super.onMeasure(
                    MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY), 
                    MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
        }
    }