95

I have a FrameLayout in which I have 2 controls: - a custom view which draws a image and some text on it - a textview with a text

I want to center both in the FrameLayout but I can't manage to do it. The Texview is centered just fine, my cusom view remains on the left side, when I make it visible.

<FrameLayout android:id="@+id/CompassMap"
               android:layout_width="fill_parent" 
               android:layout_height="wrap_content"
               android:layout_weight="1"
               android:gravity="center">

             <view class="com.MyView"
        android:id="@+id/myView"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:visibility="gone"/>

                <TextView android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:text="CENTERED" /> 
</FrameLayout>

To Mathias, I don't do anything in the constructor, it's just simple

   public class MyMapView extends View {

private int xPos = 0; 
private int yPos = 0;
private Bitmap trackMap;

private Matrix backgroundMatrix;
private Paint backgroundPaint;

private Bitmap position;
private Matrix positionMatrix;
private Paint positionPaint;

public MyMapView(Context context) {
    super(context);
    init(context, null);
}

public MyMapView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
}

public MyMapView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs);
}

private void init(final Context context, AttributeSet attrs) {

backgroundMatrix = new Matrix();
backgroundPaint = new Paint();
backgroundPaint.setFilterBitmap(true);

position = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.position);
positionMatrix = new Matrix();

positionPaint = new Paint();
positionPaint.setFilterBitmap(true);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}

@Override
protected void onDraw(Canvas canvas) {

    int width = getMeasuredWidth();
    int height = getMeasuredHeight();

    if (trackMap!=null)
    {
        Bitmap resizedBitmap = Bitmap.createScaledBitmap(trackMap, height, height, true);
        canvas.drawBitmap(resizedBitmap, backgroundMatrix, backgroundPaint);

    }

        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.translate(xPos-position.getWidth()/2, yPos-position.getHeight()/2);
        canvas.drawBitmap(position, positionMatrix, positionPaint);

        canvas.restore();
}

    public void updatePosition(int xpos, int ypos, Bitmap trackImage)
    {
        xPos=xpos;
        yPos=ypos;
        trackMap = trackImage;
        invalidate();
    }
}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Alin
  • 14,809
  • 40
  • 129
  • 218
  • 1
    Where's your custom view extended from? Sure you're handling the parameters in your constructor? – Mathias Conradt Oct 29 '10 at 12:31
  • Is there any special reason you have to use a FrameLayout and is the TextView to be displayed on top of the View? – Octavian Helm Oct 31 '10 at 15:41
  • 1
    Yeah, the FrameLayout won't let you do that. It's really just for holding a single view. If you add more to it than that it will have the exact behavior you are mentioning, it simply adds elements in a vertical stack by pinning to the upper left. http://developer.android.com/reference/android/widget/FrameLayout.html – plainjimbo Oct 31 '10 at 16:01

6 Answers6

429

We can align a view in center of the FrameLayout by setting the layout_gravity of the child view.

In XML:

android:layout_gravity="center"

In Java code:

FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;

Note: use FrameLayout.LayoutParams not the others existing LayoutParams

Milad Faridnia
  • 9,113
  • 13
  • 65
  • 78
userrp1519825
  • 4,453
  • 2
  • 14
  • 13
  • 121
    This should be the accepted answer. The other one changes the question rather than answering it. – Muz May 29 '13 at 14:27
  • Y this solution not worked for me.Adding Imageview in the center of Frame layout.cap = new ImageView(CameraActivity.this); LayoutParams params2 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params2.gravity=Gravity.CENTER; cap.setLayoutParams(params2); cameraView.addView(cap); – Akanksha Rathore Jan 09 '14 at 14:36
  • 9
    Now its worked for me. My mistake was i was imported wrong package. After 4 hours i got my mistake that the Actual package should import is android.widget.FrameLayout.LayoutParams; – Akanksha Rathore Jan 09 '14 at 18:45
  • 2
    @Akanksha that is *the only* correct answer :) you guys must use FrameLayout.LayoutParams to center a view into FrameLayout. – hector6872 Jan 20 '15 at 10:46
45

I'd suggest a RelativeLayout instead of a FrameLayout.

Assuming that you want to have the TextView always below the ImageView I'd use following layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:src="@drawable/icon"
        android:visibility="visible"/>
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_below="@id/imageview"
        android:gravity="center"
        android:text="@string/hello"/>
</RelativeLayout>

Note that if you set the visibility of an element to gone then the space that element would consume is gone whereas when you use invisible instead the space it'd consume will be preserved.

If you want to have the TextView on top of the ImageView then simply leave out the android:layout_alignParentTop or set it to false and on the TextView leave out the android:layout_below="@id/imageview" attribute. Like this.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="false"
        android:layout_centerInParent="true"
        android:src="@drawable/icon"
        android:visibility="visible"/>
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="@string/hello"/>
</RelativeLayout>

I hope this is what you were looking for.

Octavian Helm
  • 39,405
  • 19
  • 98
  • 102
  • Your explanation looks very good and it should work in my case, but it doesn't. In my RelativeLayout I have more than I said: 2 custom views, a LinearLayout, a Button and a TextView. What is curious that everything works exept my custom view. The other custom view is not influenced as it as fill_parent attributes. But, I am trying to see if I didn't missed someething. Thank you. – Alin Nov 02 '10 at 08:45
  • What is the purpose of your custom view? – Octavian Helm Nov 02 '10 at 10:19
  • I added the entire code of the custom view on the question. Basically draws a big image as background and a smaller one on x,y position. – Alin Nov 02 '10 at 16:21
  • This only works as expected if you specify a src to your ImageView. If you are trying to put text (or buttons or whatever) below a ImageView that will be populated later you'll run in to some trouble because you won't be able to know the size of your buttons or whatever until well after onResume() has finished. –  Dec 19 '10 at 17:52
  • 4
    You want to avoid RelativeLayouts wherever possible. Each RelativeLayout requires 2 measurement passes - therefore nested RelativeLayouts have an exponential measure time. Each time you add a new nested RelativeLayout, your measurement time doubles. – Martin Konecny Feb 23 '15 at 02:53
  • Cannot be the correct answer. It's a workaround for the question. – andrea.rinaldi Nov 12 '15 at 09:12
  • Please see the comment on the answer below which I 100% agree with and states that: "this 'answer' changed the question instead of answering it". We see this type of responding often where the response is beside the point, and changes the intent of the OP. This type of "non-responding" should not be deemed acceptable on this site. –  Jul 04 '21 at 11:04
8

Just follow this order

You can center any number of child in a FrameLayout.

<FrameLayout
    >
    <child1
        ....
        android:layout_gravity="center"
        .....
        />
    <Child2
        ....
        android:layout_gravity="center"
        />
</FrameLayout>

So the key is

adding android:layout_gravity="center"in the child views.

For example:

I centered a CustomView and a TextView on a FrameLayout like this

Code:

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
    <com.airbnb.lottie.LottieAnimationView
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:layout_gravity="center"
        app:lottie_fileName="red_scan.json"
        app:lottie_autoPlay="true"
        app:lottie_loop="true" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="#ffffff"
        android:textSize="10dp"
        android:textStyle="bold"
        android:padding="10dp"
        android:text="Networks Available: 1\n click to see all"
        android:gravity="center" />
</FrameLayout>

Result:

enter image description here

Rohit Singh
  • 16,950
  • 7
  • 90
  • 88
  • 1
    This was the only answer that worked for me. I have a `FrameLayout` that contains one `TextureView` and two `SurfaceView`. With this (and the `setZOrderOnTop(true);` on the Surfaces I have finally all centered overlaying – Xavi May 27 '19 at 07:12
1

Set 'center_horizontal' and 'center_vertical' or just 'center' of the layout_gravity attribute of the widget

    <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MovieActivity"
    android:id="@+id/mainContainerMovie"
    >


    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#3a3f51b5"
       />

    <ProgressBar
        android:id="@+id/movieprogressbar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal" />
</FrameLayout>
MN. Vala
  • 129
  • 1
  • 6
0

To center a view in Framelayout, there are some available tricks. The simplest one I used for my Webview and Progressbar(very similar to your two object layout), I just added android:layout_gravity="center"

Here is complete XML in case if someone else needs the same thing to do

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".WebviewPDFActivity"
    android:layout_gravity="center"
    >
    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        />
    <ProgressBar
        android:id="@+id/progress_circular"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:visibility="visible"
        android:layout_gravity="center"
        />


</FrameLayout>

Here is my output

screenshot

Abdul Rehman
  • 2,224
  • 25
  • 30
0

Following https://stackoverflow.com/a/13025031/962916, this works for me to center a TabLayout inside FrameLayout.

enter image description here

final TabLayout tabLayout = new TabLayout(this);
// Configure TabLayout...
final FrameLayout tabLayoutContainer = new FrameLayout(this);
tabLayoutContainer.setBackgroundColor(Color.RED);

final FrameLayout.LayoutParams tabLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                dpToPx(28));
final FrameLayout.LayoutParams containerLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                dpToPx(48));


tabLayoutParams.gravity = Gravity.CENTER;
tabLayoutContainer.setLayoutParams(containerLayoutParams);
tabLayoutContainer.addView(tabLayout, tabLayoutParams);
Hermandroid
  • 2,120
  • 4
  • 29
  • 35