I have a view view1 which extends FrameLayout and overrides onMeasure() like this, so that it is rendered as a square:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
Now I want to create another view view2 which extends view1, but now I want view2 to have a height equal to the parent, and hence to cover the full screen. As of now, I get it as a square too.
How do I achieve this?
In view 1:
private boolean measureAsSquare = true;
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (measureAsSquare) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setMeasureAsSquare(boolean b) {
measureAsSquare = b;
}
In View2 constructor that subclasses view 1:
public View2(Context c) {
setMeasureAsSquare(false);
}
Then you can use normal layout weight and height for view 2 to assign its preferred size.
Since the onMeasure for Square was already overridden where it disregards the height passed to it, as per your code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
One way to do what you want -- view2 which extends view1, but now I want view2 to have a height equal to the parent, and hence to cover the full screen -- is to also override onMeasure of view2 calling on setDimension like this...
public class Square2 extends Square {
public Square2(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
}
Here is a sample after I tried it out. (For code in Square View, I just copied your code in onMeasure).
Using Square:
For Squre2:
Hope this helps.
Related
I have created a custom subclass of AppCompatButton called SquareButton, which forces a button to be square. The code for that subclass was found here: https://stackoverflow.com/a/36991823/7648952.
This button works fine and displays when the layout it's contained in is inflated outside of a RecyclerView, however when used with a RecyclerView the button does not display. When I change my layout and code to use a normal Button, the Button displays, so there doesn't seem to be anything wrong with the way I'm using RecyclerView. I have no idea why this might be.
SquareButton.java:
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v7.widget.AppCompatButton;
import android.util.AttributeSet;
public class SquareButton extends AppCompatButton {
public SquareButton(Context context) {
super(context);
}
public SquareButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected 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);
}
}
Screenshot of the SquareButton working when inflated outside of a RecyclerView:
Screenshot of the SquareButton not displaying inside of RecyclerView:
Screenshot of a regular Button working inside of RecyclerView:
It seems to me that this behavior is odd. Any help would be much appreciated.
Try this code block:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if(width > height){
setMeasuredDimension(getMeasuredHeight(), getMeasuredHeight());
}else {
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
}
}
In this usage, you will set widthMeasureSpec or heightMeasureSpec instead of direct width or height value.
I implemented a custom view where I can paint. I want to set it to MATCH_PARENT, so that it fills the screen independent of the screen orientation. When I change orientation to landscape it fills just 50% of width.
I changed onMeasure() but there was no effect:
public class DrawScreen extends View{
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(context.getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){
setMeasuredDimension(screenWidth, screenHeight);
}else{
setMeasuredDimension(screenHeight, screenWidth);
}
}
}
public class MyService extends Service{
...
windowManager.addView(toolbox, params);
}
You could try the following:
final DrawScreen view = new DrawScreen(...);
final LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
view.setLayoutParams(lp);
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.
I inflate Views on ScrollView.
And I need to get event, when on scrolling one of this Views (last, for example, or special type) becomes visible (in screen zone).
If a view changes visibility, the onlayout method is called, you could try overwriting that method and check it's state.
You need to override the view's onVisibilityChanged(). This is also called when one of the view's ancestors changes visibility.
This I inflated my GridView and get what you want
public class MyGrideView extends GridView {
boolean expanded = false;
public MyGrideView(Context context) {
super(context);
}
public MyGrideView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGrideView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
Im having two custom viewgroups, superViewGroup and subViewGroup. The subviewgroup contains views. Im adding my superviewgroup to a linearLayout and the subViewGroups to my superviewgroup.
The superviewgroup onMeasure() is getting called but not in the subviewgroup. but in both cases onLayout() method is getting called.
The code as follows
public class SuperViewGroup extends ViewGroup{
public SuperViewGroup(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i("boxchart","INSIDE ON MEASURE SUPER VIEWGROUP");
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(0, 0, getWidth(), getHeight());
}
}
}
}
public class SubViewGroup extends ViewGroup{
public SubViewGroup(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i("boxchart","INSIDE ON MEASURE SUB VIEWGROUP");
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(0, 0, getWidth(), getHeight());
}
}
}
}
Comments are appreciated. thanks in advance.
Because you have to actually pass the measure to the children views:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i("boxchart","INSIDE ON MEASURE SUPER VIEWGROUP");
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
//Make or work out measurements for children here (MeasureSpec.make...)
measureChild (child, widthMeasureSpec, heightMeasureSpec);
}
}
}
Otherwise you never actually measure your children. It is up to you to decide how to do this. Just because your SuperViewGroup is in a linear layout, your SuperViewGroup takes on responsibility to measure its children.