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.
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 try to get the size of a linearlayout. I get always iactualHeight=0 in the following code:
li=(LinearLayout)findViewById(R.id.textviewerbuttonlayout);
li.requestLayout();
int iactualHeight=li.getLayoutParams().height;
My Layout is defined as follow:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:background="#FFFFFF"
android:id="#+id/textviewerlayout"
android:orientation="vertical">
<WebView
android:id="#+id/mywebview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="22" />
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textviewerbuttonlayout"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:background="#FFFFFF"
android:orientation="horizontal" >
.... BUTTONS .....
</LinearLayout>
</LinearLayout>
Somebody any idea ?
you will not get value unitl onCreate finishes.so add these in onResume() or in onStart()
int height= li.getHeight();
int width = li.getWidth();
the other option is to use globallayoutlistener(if you want to get height in onCreate) so you will get notified when li(your layout) is added.
ViewTreeObserver observer= li.getViewTreeObserver();
observer.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Log.d("Log", "Height: " + li.getHeight());
Log.d("Log", "Width: " + li.getWidth());
}
});
The problem is you are requesting the height too early. Take a look at how android draws views.
The easiest way to get the guaranteed height is to use addOnLayoutChangedListener:
View myView = findViewById(R.id.my_view);
myView.addOnLayoutChangedListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight,
int oldBottom) {
// its possible that the layout is not complete in which case
// we will get all zero values for the positions, so ignore the event
if (left == 0 && top == 0 && right == 0 && bottom == 0) {
return;
}
int height = top - bottom;
}
});
I have LinearLayout and inside 2 TextView both have marquee and when I update text in first then second TextView restarts marquee.
<LinearLayout
android:id="#+id/panel"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="bottom|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true" />
<TextView
android:id="#+id/second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="top|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
/>
</LinearLayout>
I found that if for R.id.first and R.id.second i set layout_width="320dp" the effect don't occurs.
But I want to set android:layout_width="match_parent" there is some workaround?
I found similar problem but without solution:
Android, RelativeLayout restarts Marquee-TextView when changing ImageView in same RelativeLayout
I had a similar problem and the solution IS to set fixed size for the Textview.
So why not do it progammatically? In my case, it solved the problem. Here is my solution in details :
The layout is a bit complex with a lot of changing values. Here is the interesting part :
layout.xml :
<!-- The height and visibility values change programatically -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:visibility="gone" >
<FrameLayout>
...
// some code
...
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<!-- My scrolling textview. see below. -->
<!-- The size will be set when -->
<!-- the layout will be draw, -->
<!-- after the Activity.onCreate(). -->
<!-- I removed ALL THE UNECESSARY (I mean -->
<!-- scrollHorizontally, focusable and focusableInTouchMode. -->
<!-- You don't need it !!!!) -->
<fr.cmoatoto.android.widget.ScrollingTextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever" />
<ImageView
...
// some code
... />
</LinearLayout>
</RelativeLayout>
The ScrollingTextView has been defined in this answer
Here it is again :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
public ScrollingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ScrollingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollingTextView(Context context) {
super(context);
}
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if(focused)
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
#Override
public void onWindowFocusChanged(boolean focused) {
if(focused)
super.onWindowFocusChanged(focused);
}
#Override
public boolean isFocused() {
return true;
}
}
And finally the Activity. As I said before, You need to set fixed width and height so we will do it programmatically with a listener in the onCreate() :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
LayoutParams params = v.getLayoutParams();
params.width = right - left;
params.height = bottom - top;
params.weight = 0;
v.removeOnLayoutChangeListener(this);
v.setLayoutParams(params);
}
});
}
Be careful if you need to change orientation or things like that but it works pretty well for me !
----EDIT FOR PRE-API-11---
Because OnLayoutChangeListener exists only from Api v11, there is a workaround (It works but I think it is less good) :
Remove the OnLayoutChangeListener from your activity :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
}
and add a onSizeChanged in your ScrollingTextView :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
...
// Same code as before
...
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
LayoutParams params = (LayoutParams) getLayoutParams();
params.width = w;
params.height = h;
params.weight = 0;
setLayoutParams(params);
}
}
I hope it helps !
You should prevent putting both marquee in the same ViewGroup. In your case, you can wrap each marquee TextView with a LinearLayout (this won't work if using RelativeLayout).
just a simple Fix..:) no need to worry much...just fix width of textview as some 800dp or too higher width. it will solve reset issue
I would like the items of my GridView to be square. There are 2 columns and the items width is fill_parent (e.g. they take as much horizontal space as possible. The items are custom views.
How do I make the items height to be equal to their variable width?
There is a simpler solution when GridView columns are stretched. Just override the onMeasure of the GridView item layout with...
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
Or if you want to extend a View just do something really simple like:
public class SquareImageView extends ImageView
{
public SquareImageView(final Context context)
{
super(context);
}
public SquareImageView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public SquareImageView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
{
final int width = getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
setMeasuredDimension(width, width);
}
#Override
protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh)
{
super.onSizeChanged(w, w, oldw, oldh);
}
}
It's worth noting that super.onMeasure() is not needed. onMeasured requirement is that you must call setMeasuredDimension.
I'm not sure this is possible with the current widgets. Your best bet might be to put your custom view in a custom "SquareView". This view could just contain 1 child view, and force the height to equal the width when its onLayout method is called.
I never tried to do something like that, but I think it shouldn't be too difficult. An alternative (and maybe slightly easier) solution might be to subclass your custom view's root layout (like, if it's a LinearLayout, make a SquareLinearLayout), and use that as a container instead.
edit : Here's a basic implementation which seems to work for me :
package com.mantano.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class SquareView extends ViewGroup {
public SquareView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onLayout(boolean changed, int l, int u, int r, int d) {
getChildAt(0).layout(0, 0, r-l, d-u); // Layout with max size
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View child = getChildAt(0);
child.measure(widthMeasureSpec, widthMeasureSpec);
int width = resolveSize(child.getMeasuredWidth(), widthMeasureSpec);
child.measure(width, width); // 2nd pass with the correct size
setMeasuredDimension(width, width);
}
}
It's designed to have a unique child, but I ignored all of the checks for the sake of simplicity. The basic idea is to measure the child with the width/height parameters set by the GridView (in my case, it uses numColumns=4 to calculate the width), and then do a second pass with the final dimensions, with height=width...
The layout is just a plain layout, which layouts the unique child at (0, 0) with the desired dimensions (right-left, down-up).
And here's the XML used for the GridView items :
<?xml version="1.0" encoding="utf-8"?>
<com.mantano.widget.SquareView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout android:id="#+id/item" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="horizontal"
android:gravity="center">
<TextView android:id="#+id/text" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Hello world" />
</LinearLayout>
</com.mantano.widget.SquareView>
I used a LinearLayout inside the SquareView in order to have it manage all the gravity possibilities, margins, etc.
I'm not sure how well (or bad) this widget would react to orientation and dimension changes, but it seems to work correctly.
It ends up being fairly easy to get the grid item square.
In your "GetView" method of your grid adapter, just do:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
GridView grid = (GridView)parent;
int size = grid.getRequestedColumnWidth();
TextView text = new TextView(getContext());
text.setLayoutParams(new GridView.LayoutParams(size, size));
// Whatever else you need to set on your view
return text;
}
I don`t know if it is the best way, but I accomplish that making my custom view to override onSizeChanged that way:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (getLayoutParams() != null && w != h) {
getLayoutParams().height = w;
setLayoutParams(getLayoutParams());
}
}
I use this custom view inside a LinearLayout and a GridView and in both it is showing square!
Try
<GridView
...
android:stretchMode="columnWidth" />
You can also play with other modes
This worked for me!
If you are like me and you can't use getRequestedColumnWidth() because your minSdk is lower than 16, I suggest this option.
in your fragment:
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int size = dm.widthPixels / nbColumns;
CustomAdapter adapter = new CustomAdapter(list, size, getActivity());
in your adapter (in getView(int position, View convertView, ViewGroup parent))
v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, size));
fragment.xml:
<GridView
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:horizontalSpacing="3dp"
android:verticalSpacing="3dp"
android:numColumns="4"
android:stretchMode="columnWidth" />
custom_item.xml: (for example)
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
Hope it will help someone!
if you set a static number of columns in the xml then you can take the width of the view and divide it by the number of columns.
if you are using auto_fit then it's going to be a bit tricky to get the column count ( there is no getColumnCount() method ), btw this question should help you somehow.
this is the code I'm using into the getView(...) method of the adapter with a fixed number of columns:
item_side = mFragment.holder.grid.getWidth() / N_COL;
v.getLayoutParams().height = item_side;
v.getLayoutParams().width = item_side;
This is what I am doing to show square cells in a GridView. I am not sure if you want square cells or something else.
GridView grid = new GridView( this );
grid.setColumnWidth( UIScheme.cellSize );
grid.setVerticalSpacing( UIScheme.gap );
grid.setStretchMode( GridView.STRETCH_COLUMN_WIDTH );
grid.setNumColumns( GridView.AUTO_FIT );
And then the view which I am creating for each cell I have to do the following to it:
cell.setLayoutParams( new GridView.LayoutParams(iconSize, iconSize) );
Based on SteveBorkman's answer, which is API 16+:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
GridView grid = (GridView)parent;
int size = grid.getColumnWidth();
if (convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.your_item, null);
convertView.setLayoutParams(new GridView.LayoutParams(size, size));
}
//Modify your convertView here
return convertView;
}
Along the lines of #Gregory's answer, I had to wrap my image in a LinearLayout in order to keep GridView from manipulating its dimensions from square. Note that the outer LinearLayout should be set to have the dimension of the image, and the width of the GridView column should be the width of the image PLUS any margin. For example:
<!-- LinearLayout wrapper necessary to wrap image button in order to keep square;
otherwise, the grid view distorts it into rectangle.
also, margin top and right allows the indicator overlay to extend top and right.
NB: grid width is set in filter_icon_page.xml, and must correspond to size + margin
-->
<LinearLayout
android:id="#+id/sport_icon_lay"
android:layout_width="60dp"
android:layout_height="60dp"
android:orientation="vertical"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
>
<ImageButton
android:id="#+id/sport_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:maxHeight="60dp"
android:maxWidth="60dp"
android:scaleType="fitCenter"
/>
</LinearLayout>
and the GridView like:
<GridView
android:id="#+id/grid"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:columnWidth="66dp"
android:numColumns="auto_fit"
android:verticalSpacing="25dp"
android:horizontalSpacing="24dp"
android:stretchMode="spacingWidth"
/>
In your activity
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
valX = displaymetrics.widthPixels/columns_number;
in the CustomAdapter of the GridView
v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, YourActivity.valX));