Widok środkowy Androida w FrameLayout nie działa

83

Mam FrameLayout, w którym mam 2 kontrolki: - widok niestandardowy, który rysuje obraz i tekst na nim - widok tekstu z tekstem

Chcę wyśrodkować oba w FrameLayout, ale nie mogę tego zrobić. Texview jest dobrze wyśrodkowany, mój niestandardowy widok pozostaje po lewej stronie, kiedy go pokazuję.

<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>

Dla Mathiasa nic nie robię w konstruktorze, to po prostu proste

   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();
    }
}
Alin
źródło
1
Skąd masz rozszerzony widok niestandardowy? Na pewno obsługujesz parametry w swoim konstruktorze?
Mathias Conradt
Czy jest jakiś szczególny powód, dla którego musisz używać FrameLayout i czy TextView ma być wyświetlany na górze widoku?
Octavian A. Damiean
1
Tak, FrameLayout na to nie pozwala. Tak naprawdę służy tylko do trzymania pojedynczego widoku. Jeśli dodasz do niego więcej, niż to, że będzie miał dokładnie takie zachowanie, o którym wspominasz, po prostu dodaje elementy w pionowym stosie, przypinając w lewym górnym rogu. developer.android.com/reference/android/widget/FrameLayout.html
plainjimbo

Odpowiedzi:

42

Sugerowałbym RelativeLayout zamiast FrameLayout.

Zakładając, że chcesz mieć TextView zawsze poniżej ImageView, użyłbym następującego układu.

<?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>

Zwróć uwagę, że jeśli ustawisz visibilityelement na, goneto przestrzeń, którą ten element invisiblezajmowałby, zniknie, podczas gdy gdy użyjesz zamiast tego miejsca, które zajmie, zostanie zachowane.

Jeśli chcesz, aby TextView znajdował się na wierzchu ImageView, po prostu pomiń android:layout_alignParentToplub ustaw go na falsei na TextView opuść android:layout_below="@id/imageview"atrybut. Lubię to.

<?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>

Mam nadzieję, że właśnie tego szukałeś.

Octavian A. Damiean
źródło
Twoje wyjaśnienie wygląda bardzo dobrze i powinno działać w moim przypadku, ale tak nie jest. W moim RelativeLayout mam więcej niż powiedziałem: 2 niestandardowe widoki, LinearLayout, Button i TextView. Co ciekawe, wszystko działa poza moim niestandardowym widokiem. Nie ma to wpływu na inny widok niestandardowy, ponieważ jest to atrybuty fill_parent. Ale próbuję sprawdzić, czy czegoś nie przegapiłem. Dziękuję Ci.
Alin
Jaki jest cel Twojego widoku niestandardowego?
Octavian A. Damiean
Dodałem cały kod widoku niestandardowego do pytania. Zasadniczo rysuje duży obraz jako tło i mniejszy na pozycji x, y.
Alin
Działa to zgodnie z oczekiwaniami, jeśli określisz źródło w swoim ImageView. Jeśli próbujesz umieścić tekst (lub przyciski lub cokolwiek) poniżej ImageView, który zostanie wypełniony później, napotkasz kłopoty, ponieważ nie będziesz w stanie poznać rozmiaru swoich przycisków lub czegokolwiek, aż dobrze po onResume ( ) zakończyła się.
4
Chcesz unikać RelativeLayouts wszędzie tam, gdzie to możliwe. Każdy RelativeLayout wymaga 2 przejść pomiarowych - dlatego zagnieżdżone RelativeLayout mają wykładniczy czas pomiaru. Za każdym razem, gdy dodajesz nowy zagnieżdżony układ RelativeLayout, czas pomiaru podwaja się.
Martin Konecny
389

Możemy wyrównać widok do środka FrameLayout, ustawiając layout_gravitywidok podrzędny.

W XML:

android:layout_gravity="center"

W kodzie Java:

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

Uwaga: FrameLayout.LayoutParamsnie używaj innych istniejących LayoutParams

userrp1519825
źródło
109
To powinna być akceptowana odpowiedź. Drugi raczej zmienia pytanie niż na nie odpowiada.
Muz
Y to rozwiązanie nie zadziałało. Dodanie Imageview w środku 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 (czapka);
Akanksha Rathore
8
Teraz to zadziałało dla mnie. Mój błąd polegał na tym, że zaimportowano złą paczkę. Po 4 godzinach pomyliłem się, że pakiet rzeczywisty powinien zostać zaimportowany to android.widget.FrameLayout.LayoutParams;
Akanksha Rathore
2
@Akanksha to jedyna poprawna odpowiedź :) Musicie użyć FrameLayout.LayoutParams, aby wyśrodkować widok w FrameLayout.
hrules6872
5

Po prostu wykonaj tę kolejność

Możesz wyśrodkować dowolną liczbę dzieci w FrameLayout.

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

Więc klucz jest

dodawanie android:layout_gravity="center"widoków potomnych.

Na przykład:

I skupia się CustomView i TextView na zasadzie FrameLayouttak

Kod:

<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>

Wynik:

wprowadź opis obrazu tutaj

Rohit Singh
źródło
1
To była jedyna odpowiedź, która mi pomogła. Mam, FrameLayoutktóry zawiera jeden TextureViewi dwa SurfaceView. Dzięki temu (i setZOrderOnTop(true);na powierzchniach ostatecznie wycentrowałem nakładkę
Xavi
1

Ustaw „center_horizontal” i „center_vertical” lub po prostu „środek” atrybutu layout_gravity widżetu

    <?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
źródło
0

Aby wyśrodkować widok we Framelayout, istnieje kilka dostępnych sztuczek. Najprostszy, którego użyłem w moim Webview i Progressbar (bardzo podobny do twojego układu dwóch obiektów), właśnie dodałemandroid:layout_gravity="center"

Oto pełny kod XML na wypadek, gdyby ktoś inny potrzebował tego samego

<?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>

Oto mój wynik

zrzut ekranu

Abdul Rehman
źródło