i am continuously searching and trying to sort out a issue in custom view and Relative layout.
i found multiple solution but only few of solution are usefull,but they not fulfilling my requirement completely.
partial solution 1.
partial solution 2.
via these solution i can manage the height and width of my custom view, but i just want to align my custom view in center of parent RelativeLayout,
code which i am trying throw hit-and-run is below. ;)
JAVA CODE
public class MyActiveView extends View {
public Movie mMovie;
public long movieStart;
private int gifId;
public MyActiveView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth / 2, parentHeight);
}
private void initializeView() {
InputStream is = getContext().getResources().openRawResource(R.raw.pj_logo1);
mMovie = Movie.decodeStream(is);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
super.onDraw(canvas);
long now = android.os.SystemClock.uptimeMillis();
if (movieStart == 0) {
movieStart = now;
}
if (mMovie != null) {
int relTime = (int) ((now - movieStart) % mMovie.duration());
mMovie.setTime(relTime);
mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height());
this.invalidate();
}
}
public int getActiveResource() {
return this.gifId;
}
public void setActiveResource(int resId) {
this.gifId = resId;
initializeView();
}
}
XML CODE
<?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/backsourceImagesplash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="#drawable/bg_blur" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#color/colorTransparentWhite" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:layout_centerVertical="true"
android:gravity="centre">
<pj.com.pjlib.activity_base.support_class.MyActiveView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
i want to set my custom active view layout in centre of its parent Relative Layout, but stuked in it. any help will be appreciated.
check the alignment of both image,i am trying for attribute android:layout_centerInParent="true", according to Relative layout support the "congrats image" should be in center, but it's not happening.
so i am thinking,i missed something in my custom view class but what is that, i don't know.
Change android:gravity="centre" with android:gravity="center" in Relative Layout. I think this will helpful to you.
Related
I know there is silly mistake somewhere but I can't figure out where.
I got following container's code:
public class ImagesView extends LinearLayout {
public ImagesView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ImagesView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float ar=(float)896/768;
this.setMeasuredDimension(widthSize, (int) (widthSize/5*(1f/ar)));
//this.setMeasuredDimension(1280,240);
}
}
Layout xml:
<?xml version="1.0" encoding="utf-8"?>
<com.rhyboo.net.test.ImagesView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_red_light">
<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/button3"
android:layout_weight="1" />
</com.rhyboo.net.test.ImagesView>
In android studio I can see size of my container is set correctly, but if I add something into container it displays child views as zero-sized:
What am I doing wrong?
Your onMeasure does not call super.onMeasure... so chilren are never measured. Also when calling parents onMeasure you probably want to set mode to EXACTLY for width and/or height.
I would like to have a square (same width as height) GridView fill the full height of the screen in landscape orientation. The Gridview is a chessboard (8 by 8 squares) with the xml:
<com.example.jens.jchess2.view.MyGridView
android:id="#+id/chessboard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
android:numColumns="8"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp">
</com.example.jens.jchess2.view.MyGridView>
and the elements of the grid are:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/square"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000080"
android:orientation="vertical"
android:padding="0pt">
<ImageView
android:id="#+id/square_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:padding="0pt" />
<ImageView
android:id="#+id/piece"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:padding="0pt" />
</FrameLayout>
, where the ImageViews correspond to the squares and pieces (both from png images) of the board.
In the custom MyGridView I override onMeasure as follows:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = getContext().getResources().getDisplayMetrics().heightPixels;
if (width > height) {
super.onMeasure(
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
);
} else {
super.onMeasure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
);
}
}
which gives me a square GridView in both portrait and landscape orientation. In portrait mode it fills the full width and everything is fine. In landscape mode however it extends below the screen because the height (=width) of the GridView/board is too large. It is too large by the height of the toolbar and the height of the statusbar. How can I get the proper size for the GridView, i.e. screen height minus status bar height minus toolbar height?
Start with two versions of your layout file:
/res/layout/grid.xml
...
<!-- full width -->
<com.example.MyGridView
android:layout_width="match_parent"
android:layout_height="wrap_content"
...
/>
...
/res/layout-land/grid.xml
...
<!-- full height -->
<com.example.MyGridView
android:layout_width="wrap_content"
android:layout_height="match_parent"
...
/>
...
You probably already have something like this.
Now in your onMeasure() override, the match_parent dimension will have a MeasureSpec mode of EXACTLY and the wrap_content dimension will have a MeasureSpec mode of AT_MOST. You can use this to achieve your desired layout.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST) {
// portrait
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
} else if (heightMode == MeasureSpec.EXACTLY && widthMode == MeasureSpec.AT_MOST) {
// landscape
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
EDIT: I found out that both modes can be AT_MOST depending on the ViewGroup container. Please see my other answer for updated measuring code.
Ah. Now I see that this is for a game.
Sometimes it's better to have layouts and child views, but in most cases with game boards you are better off creating a single View subclass that represents the game view.
For instance, what if your users say they want the ability to pinch-zoom into one quadrant of the game board? You can't do that with a GridView.
I whipped up a simple app to show you how this can work. I simplified the onMeasure() code I posted before, and instead of a GridView, a single View subclass renders the game board.
The MainActivity simply sets up the content view.
/res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.gameboard.MainActivity">
<com.example.gameboard.GameBoardView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
/res/layout-land/activity_main.xml:
Notice match_parent and wrap_content are switched for width and height.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.gameboard.MainActivity">
<com.example.gameboard.GameBoardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" />
</RelativeLayout>
GameBoardView.java:
public class GameBoardView extends View {
private Paint mPaint;
public GameBoardView(Context context) {
super(context);
}
public GameBoardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GameBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public GameBoardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = Math.min(width, height);
int sizeMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(sizeMeasureSpec, sizeMeasureSpec);
mPaint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = getWidth() / 8;
int h = getHeight() / 8;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
// choose black or white depending on the square
mPaint.setColor((row + col) % 2 == 0 ? 0xFFFFFFFF : 0xFF000000);
canvas.drawRect(w * col, h * row, w * (col + 1), h * (row + 1), mPaint);
}
}
}
}
Here I'm just drawing the squares right in the view. Now, if I were making a chess game, I would also create a Drawable subclass that would take the game model and render it. Having a separate Drawable for rendering the game makes it easy to scale to the correct size. For example, your Drawable could render at a fixed constant size, then be scaled by the View subclass to fit. The View subclass would function mostly as a controller, interpreting touch events and updating the game model.
I have made a Custom ViewGroup. Detail about this Custom ViewGroup is found here from my earlier question. The problem I am facing here is , whenever I try to add buttons in the LinearLayout that is inside the custom Viewgroup, the buttons never get shown. I have tried many things but the button is never displayed, do I have to do something in the custom viewgroup, I even tried inflating the button but still did not work.
Code for Custom ViewGroup:
public class RootViewLayout extends ViewGroup {
private View mDrawView;
private View mSlideView;
private int mTop;
private int mDragRange;
public RootViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
mDrawView = findViewById(R.id.content_frame_white);
mSlideView = findViewById(R.id.slide_frame);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom){
bringChildToFront(mDrawView);
mDrawView.layout(0, 0, right, bottom);
mSlideView.layout(0, 0, right/2, bottom);
}
}
and the XML :
<com.example.drawapp.RootViewLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Root_View_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<com.example.drawapp.DrawView
android:id="#+id/content_frame_white"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/whitepaperwithcoffeestain">
</com.example.drawapp.DrawView>
<LinearLayout
android:id="#+id/slide_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#drawable/slidebackgrd"
android:orientation="vertical">
<Button
android:id="#+id/pen"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:background="#drawable/pic"/>
</LinearLayout>
</com.example.drawapp.RootViewLayout>
sorry for the late comment.if you didn't solve it yet,apparently you have to do the same to your button what you did for your LinearLayout
View b= mSlideView.findViewById(R.id.pen);
b.layout(0, 0, right/4, bottom);
checked it and it displayed the buttons width as half of the linearlayout and height as the bottom parameter
I create my own class for the square layout:
public class SquareLayout extends LinearLayout{
public SquareLayout(Context context) {
super(context);
}
public SquareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#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);
}
Then, in my xml:
...
<com.myApp.SquareLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:orientation="horizontal" >
<ImageView
android:id="#+id/cellImageView"
android:adjustViewBounds="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:padding="2dp"
android:scaleType="centerCrop"
android:src="#drawable/image" />
</com.myApp.SquareLayout>
...
Nothing written more in my java code.
But instead if my layout and my Image, I see only a white rectangle...
What am I wrong?
// you forget to call super.onMeasure(widthMeasureSpec, widthMeasureSpec);
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width > height ? height : width;
setMeasuredDimension(size, size);
}
// xml file
<com.example.testapplication.SquareLayout
android:id="#+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:orientation="horizontal" >
<ImageView
android:id="#+id/cellImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:adjustViewBounds="true"
android:padding="2dp"
android:scaleType="centerCrop"
android:src="#drawable/ic_launcher" />
</com.example.testapplication.SquareLayout>
I had problems calling setMeasuredDimension directly when applying the same technique to a RelativeLayout. I was unable to correctly align against the bottom edge. Changing to instead call up to super.onMeasure() with a new measure spec worked better.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = Math.min(width, height);
super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
}
Edit:
The solution below has now been deprecated, as ConstraintLayout has become the new standard and provides this functionality.
Original Answer:
Turns out the Android team gave us the solution, but nobody knows about it! Check out these two classes from the Percent Support Library:
PercentFrameLayout
PercentRelativeLayout
If you want to impose the ratio of a view, you have to place it within one of these layouts. So in this case, you have to place a standard LinearLayout, not your subclass, within one of these layouts with the right aspect ratio. Example if you want to use a PercentFrameLayout:
<android.support.percent.PercentFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_aspectRatio="100%">
<!-- Whatever subviews you want here -->
</LinearLayout>
</android.support.percent.PercentFrameLayout>
And there you go, all your views will be contained within a square linear
layout!
don't forget to add the gradle dependency compile 'com.android.support:percent:23.3.0' Adjust the version number as required
I'm getting a problem with a part of my Android application. I need to draw a graph in a custom Dialog box but it doesn't work even when I follow all the solutions found on the internet. My goal is to show a Dialog box when a user is clicking on a button on my main frame. To do this, I want to draw it in a very simple Dialog Box. My graph need to be "scrollable" because it can be bigger than the Dialog box. Here are the sources codes :
public class GraphDialog extends Dialog implements android.view.View.OnClickListener
{
Canvas canvas;
public GraphDialog(Context context)
{
super(context);
System.out.println("Test");
this.setContentView(R.layout.dialog_graph_layout);
this.setTitle(R.string.title_dialog_graph);
((Button) this.findViewById(R.id.button_ok)).setOnClickListener(this);
}
#Override
public void onClick(View v)
{
Controller.getPollManager().setPoll(null);
Controller.getPollManager().setTab(null);
this.cancel();
}
}
Here is my xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<ScrollView
android:id="#+id/scroll_layout"
android:layout_width="500px"
android:layout_height="800px"
android:layout_weight="1"
android:drawingCacheQuality="low"
android:scrollbars="vertical" >
<be.ac.ucl.lfsab1509.proxipoll.GraphView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</be.ac.ucl.lfsab1509.proxipoll.GraphView>
</ScrollView>
<Button
android:id="#+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="0"
android:text="#string/ok" />
</LinearLayout>
And here is my custom View :
public class GraphView extends View
{
Paint paint;
public GraphView(Context context)
{
super(context);
System.out.println("test GraphView");
this.setWillNotDraw(false);
init();
}
public GraphView(Context context, AttributeSet attrs)
{
super(context, attrs);
System.out.println("test GraphView");
this.setWillNotDraw(false);
init();
}
public void init()
{
paint = new Paint();
paint.setColor(Color.BLACK);
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
System.out.println("test onDraw");
canvas.drawText(Controller.getPollManager().getPoll().name, 50, 50, paint);
this.draw(canvas);
}
}
To check what goes wrong, you can see that I have added some println(). When I try to show the Dialog box, I get all lines except the on of the onDraw() method. Does someone know what to do to make it work ?
Thank you
Try overriding onMeasure: when I last did any custom charting, I needed to do something like this.
#Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
{
viewWidth = MeasureSpec.getSize( widthMeasureSpec );
viewHeight = MeasureSpec.getSize( heightMeasureSpec );
if(box.getWidth() != 0){
// use the screen width: oldViewWidth -> screenWidth, viewWidth -> maxXRange
boxWidth = box.getWidth() - box.getPaddingRight() - box.getPaddingLeft() - 10;
if(screenWidth <= 0) viewWidth = boxWidth;
else viewWidth = (int)((getMaxXRange()*boxWidth)/screenWidth);
if(viewWidth < boxWidth) viewWidth = boxWidth;
}
setMeasuredDimension( viewWidth, viewHeight );
}
This basically checks the size of the window and tells the graphics layer how big I want it to be.