2016-03-22 30 views
7

Czy można zmienić ograniczenia RelativeLayout po ich ustawieniu jeden raz?Xamarin.Forms: Zmień ograniczenia RelativeLayout później

W dokumentacji widzę metody takie jak GetBoundsConstraint(BindableObject), ale myślę, że możesz ich używać tylko, jeśli masz plik XAML. Na razie próbuję to zrobić w kodzie. Mam null jeśli staram

RelativeLayout.GetBoundsConstraint(this.label); 

Jedynym sposobem znalazłem się jest usunięcie dzieci z układu i dodać go do nowych ograniczeń ponownie.

Przykład:

public class TestPage : ContentPage 
{ 
    private RelativeLayout relativeLayout; 
    private BoxView view; 
    private bool moreWidth = false; 

    public TestPage() 
    { 
     this.view = new BoxView 
     { 
      BackgroundColor = Color.Yellow, 
     }; 

     Button button = new Button 
     { 
      Text = "change", 
      TextColor = Color.Black, 
     }; 

     button.Clicked += Button_Clicked; 

     this.relativeLayout = new RelativeLayout(); 

     this.relativeLayout.Children.Add(this.view, 
      Constraint.Constant(0), 
      Constraint.Constant(0), 
      Constraint.Constant(80), 
      Constraint.RelativeToParent((parent) => 
      { 
       return parent.Height; 
      })); 

     this.relativeLayout.Children.Add(button, 
      Constraint.RelativeToParent((parent) => 
      { 
       return parent.Width/2; 
      }), 
      Constraint.RelativeToParent((parent) => 
      { 
       return parent.Height/2; 
      })); 

     this.Content = this.relativeLayout; 
    } 

    private void Button_Clicked(object sender, EventArgs e) 
    { 
     double width = 0; 
     if(this.moreWidth) 
     { 
      width = 120; 
     } 
     else 
     { 
      width = 80; 
     } 
     var c= BoundsConstraint.FromExpression((Expression<Func<Rectangle>>)(() => new Rectangle(0, 0, width, this.Content.Height)), new View[0]); 
     RelativeLayout.SetBoundsConstraint(this.view, c); 
     this.relativeLayout.ForceLayout(); 
     this.moreWidth = !this.moreWidth; 
    } 
} 

Odpowiedz

11

To nie oficjalnie możliwe przy obecnej wersji Formularzy Xamarin. Kontener RelativeLayout dokonuje ponownej kalkulacji ograniczeń podczas dodawania/usuwania elementów z kolekcji podrzędnej (buforuje rozwiązane ograniczenia - przypuszczalnie dla wydajności). Mimo że różne ograniczenia są implementowane jako właściwości Bindable, nadal nie są one obliczane ponownie po zmianie.

Zakładam, że intencją jest, aby pewnego dnia szanować aktualizacje wiązań, które byłyby użyteczne na przykład w przypadku animacji, ale na razie wygląda na to, że nie działa w ten sposób.

JEDNAK, wziąłem spojrzenie na decompiled źródło RelativeLayout i jest można włamać razem sposób wokół niego - ale może nie własnych potrzeb, w zależności od tego, ile funkcjonalność potrzebna i jak skomplikowane Twoje definicje ograniczeń są.

Zobacz ten przykładowy kod (kluczowym elementem jest ustawienie ograniczenia korzystając SetBoundsConstraint, który nadpisuje wewnętrznie obliczone granice dodanego widzenia - a potem dzwoni ForceLayout()):

public partial class App : Application 
{ 
    public App() 
    { 
     var label = new Label { 
      Text = "Test", 
      HorizontalTextAlignment = TextAlignment.Center, 
      VerticalTextAlignment = TextAlignment.Center, 
      BackgroundColor = Color.Silver 
     }; 
     var layout = new RelativeLayout(); 
     layout.Children.Add (label, 
      Constraint.Constant (50), 
      Constraint.Constant (100), 
      Constraint.Constant (260), 
      Constraint.Constant (30)); 
     MainPage = new ContentPage { 
      Content = layout 
     }; 

     var fwd = true; 
     layout.Animate ("bounce", 
      (delta) => { 
       var d = fwd ? delta : 1.0 - delta; 
       var y = 100.0 + (50.0 * d); 
       var c = BoundsConstraint.FromExpression ((Expression<Func<Rectangle>>)(() => new Rectangle (50, y, 260, 30)), new View [0]); 
       RelativeLayout.SetBoundsConstraint(label, c); 
       layout.ForceLayout(); 
      }, 16, 800, Easing.SinInOut, (f, b) => { 
       // reset direction 
       fwd = !fwd; 
      },() => { 
       // keep bouncing 
       return true; 
      }); 
    } 
} 
+0

Dzięki za znakomitą odpowiedź! Czy można używać 'BoundsConstraint.FromExpression' razem z' Constraint.RelativeToParent'? Czy możesz tylko ustawić wartości dla 'Rectangle'? Co próbuję zrobić, to zmienić szerokość elementu, który zajmuje połowę ekranu. Dlatego musisz znać wysokość nadrzędną. Obecnie używam 'this.Content.Height', który wydaje się działać. Chociaż muszę przetestować to dalej. – testing

+1

Powinno działać tak, o ile wszystkie ograniczenia dla modyfikowanego elementu są stałe lub względne (ograniczenie BoundsConstraint jest kombinacją wszystkich czterech ograniczeń x/y/width/height, więc wszystkie te muszą spełnić to kryteria). Jeśli któryś z nich korzysta z RelativeToView, to musisz przekazać te widoki w tablicy jako drugi parametr 'FromExpression()'. Trudno powiedzieć na pewno, jeśli ten hack będzie działał dla niczego oprócz Stałego, chyba że go wypróbujesz. Oczywiście zależy to od wewnętrznych elementów, które mogą zostać uszkodzone w następnej wersji XF. –

+0

Próbowałem pracować z 'RelativeToParent', ale walczyłem z użyciem poprawnej notacji. Zamiast stałej próbowałem użyć 'Constraint.RelativeToParent ((parent) => {return parent.Height;})', ale dostałem komunikat jak * zbyt wiele parametrów *. Czy to działa? – testing

1

Jeśli ja zrozumiałem, że by spróbować następujących

Wdrożenie SizeChanged imprezę dla relativeLayout

jak: -

var relativeLayout = new RelativeLayout(); 

relativeLayout.SizeChanged += someEventForTesting; 

i wywołaj zdarzenie, gdy chcesz zmienić rozmiar względnego układu lub określonego dziecka.

public void someEventForTesting(Object sender , EventArgs) 
{ 
var layout = (RelativeLayout)sender ; 
//here you have access to layout and every child , you can add them again with new constraint . 
} 
+0

Jeśli zostanie wywołane zdarzenie "SizeChanged", mam dostęp do więzów? Jak mogę wywołać zdarzenie 'SizeChanged' z odpowiednim' RelativeLayout'? – testing

+0

Zdarzenie 'SizeChanged' nie oferuje żadnych korzyści, chyba że używasz' Grid' do układu i ręcznego pozycjonowania/zmiany rozmiaru elementów treści w kodzie. Ponadto, aby wywołać zdarzenie "SizeChanged", należy zmienić rozmiar kontenera - co może być dość kosztowną czynnością, jeśli istnieje wiele widoków podrzędnych. –

+0

@ testowanie - Jak słusznie zauważył Keith, może to być praca ekstensywna, gdy masz dużo dzieci, , aby wywołać zdarzenie po prostu dodać coś do konkretnego układu, spróbuje zmienić kontener i wydarzenie zostanie zwolnione, w przypadku, u przepisać cały relativeLayout, jeśli możesz, lub zmienić pozycję dzieci, na które będą miały wpływ. Wyobraź sobie sytuację (czysto hipotetyczną): - masz układ z 4 przyciskami na nim. Chcesz kliknąć czwartą i dostać nowy btn pojawiający się prawo do czwartego. w tym scenariuszu. na zdarzeniu kliknięcia bttn, możesz odpalić rozmiarChange i wykonać tam pracę –