Jak programowo zmienić rozmiar widoku niestandardowego?

164

Koduję widok niestandardowy rozszerzony z RelativeLayout i chcę programowo zmienić jego rozmiar. Jak mogę to zrobić?

klasa widoku niestandardowego jest podobna do:

public ActiveSlideView(Context context, AttributeSet attr){
        super(context, attr);
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if(inflater != null){       
            inflater.inflate(R.layout.active_slide, this);
        }
herbertD
źródło

Odpowiedzi:

253

Android zgłasza wyjątek, jeśli nie uda się przekazać wysokości lub szerokości widoku. Zamiast tworzyć nowy obiekt LayoutParams, użyj oryginalnego, aby zachować wszystkie inne ustawione parametry. Zwróć uwagę, że typ LayoutParams zwracany przez getLayoutParams jest typem układu nadrzędnego , a nie widoku, którego rozmiar zmieniasz.

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) someLayout.getLayoutParams();
params.height = 130;
someLayout.setLayoutParams(params);
smisiewicz
źródło
2
Jak wspomina @HerbertD, otrzymuję również błąd, robiąc to, chyba że używam LinearLayout.LayoutParams, nawet jeśli jest to RelativeLayout, którego rozmiar zmieniam.
Martin Belcher - AtWrk
6
@Eigo Zgodnie z dokumentacją Androida, LayoutParams są przekazywane do widoku nadrzędnego, ponieważ jest to widok odpowiedzialny za układ.
sstn
1
Czy wartość in powinna zostać przekonwertowana na wartość dp, czy zadziała.
Dory
Jest to również zalecane, ponieważ pozwala uniknąć niepotrzebnego tworzenia wystąpienia nowego obiektu LayoutParams
Stephen Kidson
129
this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, theSizeIWant));

Problem rozwiązany!

UWAGA: Upewnij się, że używasz układu nadrzędnego LayoutParams. Mój jest LinearLayout.LayoutParams!

herbertD
źródło
3
Wut. Dlaczego nie używałbyśRelativeLayout.LayoutParams?
NMR,
1
To nie zadziałało dla mnie, mam za to wyjątek klasy.
Tapan Thaker,
4
@Tapan Thanker Użyj LayoutParams układu nadrzędnego. A układ My Parent to LinearLayout.
herbertD
10
Napisałem bardziej ogólną wersję tego: private void resizeView(View view, int newWidth, int newHeight) { try { Constructor<? extends LayoutParams> ctor = view.getLayoutParams().getClass().getDeclaredConstructor(int.class, int.class); view.setLayoutParams(ctor.newInstance(newWidth, newHeight)); } catch (Exception e) { e.printStackTrace(); } }
atroutt
2
Spowoduje to zresetowanie wszystkich pozostałych parametrów do wartości domyślnych. @smisiewicz odpowiedź jest lepsza.
Fran Marzoa,
66

To działa dla mnie:

ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();
Sileria
źródło
7
Jest to znacznie lepsze niż inne odpowiedzi, ponieważ ten kod nie wymaga znajomości dokładnego typu nadrzędnej grupy ViewGroup.
Bart Burg
1
Czy wiesz, jaka jest różnica między wywołaniem requestLayout () a wywołaniem setLayoutParams (params)?
voghDev
2
setLayoutParams (params) zawiera requestLayout ().
illusionJJ
44

Powiedzmy, że chcesz zmienić rozmiar widoku w pikselach niezależnych od urządzenia ( dp ): -

Musisz użyć metody o nazwie applyDimension, która jest członkiem klasy TypedValuedo konwersji z pikseli na dps. Więc jeśli chcę ustawić wysokość na 150 dp (powiedzmy) - wtedy mógłbym to zrobić:

float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) someLayout.getLayoutParams();
params.height = (int) pixels;
someLayout.setLayoutParams(params);

gdzie wyrażenie: getResources().getDisplayMetrics()pobiera gęstość / rozdzielczość ekranu

Danield
źródło
6
Zamiast na float pixels = context.getResources().getDimensionPixelSize(R.dimen.card_height);
stałe
ta odpowiedź jest bardziej odpowiednia jako poprawna odpowiedź !. Dzięki
Yunus Kulyyev
19

W Kotlinie możesz użyć rozszerzeń ktx :

yourView.updateLayoutParams {
   height = <YOUR_HEIGHT>
}
Phil
źródło
2
To jest niesamowite!
user1032613
6

spróbuj tego:

...
View view = inflater.inflate(R.layout.active_slide, this);
view.setMinimumWidth(200);
zed_0xff
źródło
Przepraszam, że nie opublikowałem wszystkich pytań, odkąd na nie odpowiedziałeś. To jest całe pytanie. Dzięki!
herbertD
6

Oto bardziej ogólna wersja powyższego rozwiązania z @herbertD:

private void resizeView(View view, int newWidth, int newHeight) { 
    try { 
        Constructor<? extends LayoutParams> ctor = view.getLayoutParams().getClass().getDeclaredConstructor(int.class, int.class); 
        view.setLayoutParams(ctor.newInstance(newWidth, newHeight));   
    } catch (Exception e) { 
        e.printStackTrace(); 
    }
}
atroutt
źródło
@atroutt, dosłownie uratowałeś mi dzień :)
Qasim
5

W ten sposób zwiększyłem szerokość widoku niestandardowego

customDrawingView.post(new Runnable() {
                            @Override
                            public void run() {
                                View view_instance = customDrawingView;
                                android.view.ViewGroup.LayoutParams params = view_instance
                                        .getLayoutParams();
                                int newLayoutWidth = customDrawingView
                                        .getWidth()
                                        + customDrawingView.getWidth();
                                params.width = newLayoutWidth;
                                view_instance.setLayoutParams(params);
                                screenWidthBackup = params.width;
                            }
                        });
AkhilGite
źródło
4

Rozwiązałem to w ten sposób… Mam w zasadzie prosty widok wewnątrz pliku xml.

 View viewname = findViewById(R.id.prod_extra);
             prodExtra.getLayoutParams().height=64;
Aplikacje DazzleGifts
źródło
2
haha, bardzo naiwny, ale dobrze działający sposób, jednak polecam wywołanie metody setLayoutParams () w celu poprawnego propagowania zmiany do ewentualnych zagnieżdżonych dzieci, więc po zaktualizowaniu .width i .height wywołaj view.setLayoutParams (view.getLayoutParams ()) to też jest dowód zawsze typu
comeGetSome
@Bhargav Rao, czy możesz mi pomóc w tym temacie: https://stackoverflow.com/q/44259342/6596724
tux-world
2

Jeśli masz tylko two or three condition(sizes), możesz użyć @Overide onMeasure jak

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

I łatwo zmień swój rozmiar dla tych warunków w klasie CustomView.

Xar-e-ahmer Khan
źródło
1

jeśli zastępujesz onMeasure, nie zapomnij zaktualizować nowych rozmiarów

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(newWidth, newHeight);
}
XurajB
źródło
1

W ten sposób to osiągnąłem. W odpowiedzi Sileria wykonał następujące czynności:

ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();

To prawda, ale oczekuje, że podamy wysokość pixels, ale chciałem podać wysokość, dpktórą chcę, więc dodałem:

public int convertDpToPixelInt(float dp, Context context) {
    return (int) (dp * (((float) context.getResources().getDisplayMetrics().densityDpi) / 160.0f));
}

Więc będzie to wyglądać tak:

ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = convertDpToPixelInt(50, getContext());
layout.requestLayout();
Klasa A
źródło
0

Oto co zrobiłem:

View myView;  
myView.getLayoutParams().height = 32;  
myView.getLayoutParams().width = 32;

Jeśli istnieje grupa widoków, do której należy ten widok, może być konieczne wywołanie metody yourViewGroup.requestLayout (), aby odniosła skutek.

us_david
źródło