I am trying to make a relative layout bounded within a circle i.e the relative layout should be like the square shown in the figure below.
I am trying to set width and height of the layout as:
√((diameter)²/2) which is about 70 %
(source: yogaflavoredlife.com)
public class SquareLayout extends RelativeLayout {
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
int required = Math.min(originalWidth, originalHeight) * 7 / 10;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(required, required);
}
}
What I am getting is a rectangular layout instead of square layout:
Can anyone guide me where I am going wrong?
Sample usage:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.widget.SquareLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F55C5C">
</com.example.widget.SquareLayout>
</RelativeLayout>
Here's how I got the solution. First I created a square frame to hold all the layouts.
public class SquareFrame extends FrameLayout {
public SquareFrame(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
int required = Math.min(originalWidth, originalHeight);
super.onMeasure(
MeasureSpec.makeMeasureSpec(required, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(required, MeasureSpec.EXACTLY));
}
}
Then inserted all layouts within that square frame.
<com.example.widget.SquareFrame
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#5CF5FC">
<com.example.widget.SquareLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F55C5C">
</com.example.widget.SquareLayout>
</com.example.widget.SquareFrame>
Here is what I got
a square, not a rectangle.
Related
I have a custom view as element in my recyclerview but it takes more spaces as need broken the alignment if the left text views has different lenght.
MyCustomClass
[...]
public MyCustomClass(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentHeight, parentHeight);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void setupPaint() {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(faceRadius,faceRadius);
setLayoutParams(params);
//paint setup
}
[...]
LIST LINE XML FILE
[...]
<LinearLayout
android:id="#+id/linear_one"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="right|center_vertical"
android:orientation="horizontal">
<view
android:id="#+id/layout_two"
class="example.android.cv.MyCustomView"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
</LinearLayout>
[...]
Now I obtain this, but i want to reduce the width to get a "square custom view" around the smiley face.
I have a RelativeLayout with the weight property for width , and using the 130dp for height , but it seem's like a rectangle and now i want height equal to width (i want to achieve to square style) , like this image :
this is my xml :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="130dp"
android:layout_marginRight="2dp"
android:layout_weight="1"
android:background="#00c4ff"
android:onClick="blockClick">
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="130dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_weight="1"
android:background="#00c4ff"
android:onClick="blockClick">
</RelativeLayout>
</LinearLayout>
Make your own implementation of RelativeLayout
Code sample for aspect ratio ImageView
Code example:
public class MyRelativeLayout extends RelativeLayout{
[...]
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newWidth = getMeasuredWidth();
int newHeight = newWidth;
setMeasuredDimension(newWidth, newHeight);
}
[...]
}
Use custom RelativeLayout...
public class SquareRelativeLayout extends RelativeLayout {
public SquareRelativeLayout(Context context) {
super(context);
}
public SquareRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width);
}
}
Thinking about different screen of device, there is one solution:
Get the width of the screen. W
divide the W: W/2
Set every height of the RelativeLayout with W/2
I have used this solution to set the image View with fix ratio on different screen.
layout.width = getResources().getDisplayMetrics().widthPixels;
layout.height = (int) (layout.width / (2.0));
mRelativeView.setLayoutParams(layout);
I am creating a custom LinearLayout just to measure and properly resize it:
public class Frame extends LinearLayout
{
private int width;
private int height;
private Context context;
public Frame(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context=context;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int newwidth=MeasureSpec
.makeMeasureSpec(height*480/720,MeasureSpec.EXACTLY);
super.onMeasure(newwidth, heightMeasureSpec);
}
}
It works perfectly, but it obviously keeps its position on the place before the measure changed so it is not centered horizontally anymore. How can I override the settings in my custom LinearLayout to make it appear in the horizontal center?
This is how I call it in he xml file:
com.myproject.main.Frame
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/button"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal"
android:weightSum="480" >
I'm using GridView in my app:
<GridView
android:id="#+id/main_grid_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="4" >
</GridView>
Every cell in this GridView is ImageView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:contentDescription="#string/img"
android:scaleType="centerCrop" />
</RelativeLayout>
All cells in my GridView must be square (height must equals width) and image must fit cell. But it always looks like rectangle... How I can to implements square cells in GridView?
Make sure your cell is square.
For this, you can set the width and height of the RelativeLayout programmatically with the value screen_width/4.
This can do the trick
#Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width > height ? height : width;
setMeasuredDimension(size, size);
}
As mentioned in the answer here - Gridview with two columns and auto resized images
You can make a custom ImageView for this
public class SquareImageView extends ImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
public SquareImageView(Context context, AttributeSet attributeSet, int defStyle) {
super(context, attributeSet, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
} else {
setMeasuredDimension(getMeasuredHeight(), getMeasuredHeight());
}
}
}
and then use this in your grid view cell layout as
<package_containing_SquareImageView.SquareImageView
android:layout_width="match_parent"
android:layout_height="match_parent" />
I'm writing a custom View object, but I can't seem to get it to measure correctly. By looking at the View source code, I thought calling setMinimumHeight() and setMinimumWidth() would be enough (that's really all I need, a minimum size that the parent layout should respect). Here's my code:
public class MonthView extends View {
private final int minCellSize = 24;
public MonthView(Context context) {
super(context);
}
public MonthView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MonthView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final float scale = getContext().getResources().getDisplayMetrics().density;
setMinimumHeight((int) (minCellSize * scale * 6));
setMinimumWidth((int) (minCellSize * scale * 7));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
}
}
Pretty simple. I then embed it in a LinearLayout, something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.foghina.adtp.MonthView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="I am below the monthview!"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
However, the MonthView takes up the entire screen and the TextView is not visible. How can I correctly write my View so that it has a minimum height / width when wrap_content is used?
I figured it out eventually. I had to write my own version of View.getDefaultSize() that is just slightly different. Here's how I used it:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final float scale = getContext().getResources().getDisplayMetrics().density;
setMeasuredDimension(getSize((int) (minCellSize * scale * 7), widthMeasureSpec),
getSize((int) (minCellSize * scale * 6), heightMeasureSpec));
}
private static int getSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
result = size < specSize ? size : specSize;
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
Pretty nasty. I don't understand why the default View.getDefaultSize() doesn't work like that.
I think you must use setMeasureDimension()