Android - jak ustawić Widok poza ekranem?

Próbuję animować prosty ImageView w mojej aplikacji i chcę, aby wsunął się od dołu ekranu i doszedł do pozycji spoczynkowej, w której górne 50px widoku znajduje się poza górną częścią ekranu (np. ostateczna pozycja ImageView powinna wynosić-50px w X). Próbowałem użyć AbsoluteLayout, aby to zrobić, ale to faktycznie odcina top 50px ImageView tak, że top 50px nigdy nie jest renderowany. Muszę mieć top 50px ImageView widoczny / renderowany podczas animuje się, a następnie po prostu odpoczywa nieco poza ekranem. Mam nadzieję, że wystarczająco dobrze to wyjaśniłem.

Oto, czego obecnie używam jako układu i animacji slajdów (obecnie nie renderuje to top 50px ImageView):

Układ:

<?xml version="1.0" encoding="utf-8"?>
   <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_height="fill_parent" 
      android:layout_width="fill_parent" 
      android:id="@+id/QuickPlayClipLayout">
      <ImageView android:id="@+id/Clip"
         android:background="@drawable/clip" 
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content" 
         android:layout_y="-50dp">
      </ImageView>
   </AbsoluteLayout>

Animacja:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
   <translate android:fromYDelta="100%p" 
       android:toYDelta="0"
       android:duration="1000"/>
   <alpha android:fromAlpha="0.0" 
       android:toAlpha="1.0"
       android:duration="1000" />
</set>
Z góry dzięki.
Author: RyanM, 2010-03-31

6 answers

Wymyśliłem rozwiązanie, które powinno być łatwe do wdrożenia. Polega na modyfikowaniu układu i czynności nadmuchiwania układu... patrz poniżej:

Activity (QuickPlay.java): {]}

public class QuickPlay extends Activity implements AnimationListener
{
    private ImageView myImageView;
    private LinearLayout LL;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.quick_play_screen);

        myImageView = (ImageView) this.findViewById(R.id.Clip);
        LL = (LinearLayout) this.findViewById(R.id.QuickPlayClipLayout);

        //finally
        Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_in_quickplay);
        anim.setAnimationListener(this);
        LL.startAnimation(anim);
    }
    @Override
    public void onAnimationEnd(Animation animation){}

    @Override
    public void onAnimationRepeat(Animation animation){}

    @Override
    public void onAnimationStart(Animation animation)
    {
        // This is the key...
        //set the coordinates for the bounds (left, top, right, bottom) based on the offset value (50px) in a resource XML
        LL.layout(0, -(int)this.getResources().getDimension(R.dimen.quickplay_offset), 
                LL.getWidth(), LL.getHeight() + (int)this.getResources().getDimension(R.dimen.quickplay_offset));
    }
}

New LinearLayout (CustomLinearLayout.java): {]}

public class CustomLinearLayout extends LinearLayout
{
    private Context myContext;

    public CustomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        myContext = context;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec+((int)myContext.getResources().getDimension(R.dimen.quickplay_offset)));
    }
}

Layout (/res / layout / quick_play_screen.xml):

<?xml version="1.0" encoding="utf-8"?>
   <com.games.mygame.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_height="fill_parent" 
      android:layout_width="fill_parent" 
      android:id="@+id/QuickPlayClipLayout">
      <ImageView android:id="@+id/Clip"
         android:background="@drawable/clip" 
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content">
      </ImageView>
   </com.games.mygame.CustomLinearLayout>

Resource (/res/values / constants.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="quickplay_offset">50dp</dimen>
</resources>

Animacja (/res / anim / slide_in_quickplay.xml):

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
   <translate android:fromYDelta="100%p" 
       android:toYDelta="0"
       android:duration="1000"/>
   <alpha android:fromAlpha="0.0" 
       android:toAlpha="1.0"
       android:duration="1000" />
</set>

Program robi teraz dokładnie to, co ja muszę to zrobić. Cały układ zaczyna się od ekranu na dole, przesuwa się w ciągu 1 sekundy i przechodzi w stan spoczynku, gdzie góra układu jest w rzeczywistości 50px od góry ekranu (tj. LL.getTop() = -50), a dół układu spoczywa na dole ekranu (tj. LL.getBottom() = 530 = 480 + 50).

 33
Author: RyanM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-13 20:29:58

Aby ustawić mój widok poza ekranem użyłem następującego kodu:

View myView = /* view you want to position offscreen */
int amountOffscreen = (int)(myView.getWidth() * 0.8); /* or whatever */
boolean offscreen = /* true or false */


int xOffset = (offscreen) ? amountOffscreen : 0;
RelativeLayout.LayoutParams rlParams = 
    (RelativeLayout.LayoutParams)myView.getLayoutParams();
rlParams.setMargins(-1*xOffset, 0, xOffset, 0);
myView.setLayoutParams(rlParams);

Ten kod pozycjonuje myView poza ekranem według amountOffscreen, co w tym przypadku umieszcza 80% widoku poza ekranem, pozostawiając tylko 20% na ekranie.

Nie używaj bezpośrednio metody layout () - Android będzie wykonywał kolejne wywołania w celu unieważnienia widoku z losowych powodów i tylko layoutParams są utrzymywane w trakcie unieważniania połączeń. Jeśli jesteś ciekawy, sprawdź linie 904 do 912 tego pliku , aby zobaczyć, dlaczego trzeba zmodyfikować layoutParams.

 30
Author: esilver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-25 12:55:21

Zamiast tego możemy w prosty sposób podać ujemne wartości layout_margin(Góra / Lewo / Prawo/Dół) na przykład: jeśli chcesz, aby Widok był wyłączony od góry ekranu, możesz podać

android:layout_marginTop="-40dp"
 27
Author: arun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-11 13:20:43

Jest to łatwe do zrobienia, jeśli skoczysz do korzystania z Canvas; te obsługują rysowanie z ekranu bez żadnych problemów. Będzie to jednak bardziej skomplikowane do wdrożenia. Musisz zaimplementować własne View i napisać własną animację w kodzie. Zasadniczo sprowadza się to do prostej obsługi grafiki 2D, a nie widoków za pomocą wbudowanych animacji XML. Może jest sposób, aby to zrobić z XML, ale jestem znacznie bardziej zaznajomiony z płótna. Bardzo dobrym miejscem, aby zobaczyć jak to jest obsługiwane w kodzie jest przykładowa gra Lunar Lander dostarczana wraz z zestawem SDK.

Mniej więcej kroki, które musisz wykonać to:

  1. Umieść niestandardowy widok w pliku XML, używając czegoś w rodzaju <your.package.AnimatingView>, ustawiając jego rozmiar na fill-parent.

  2. Następnie zdefiniuj klasę AnimatingView, która extends SurfaceView and implements SurfaceHolder.Callback. (Daje to dostęp do rysunku Canvas natychmiast, a nie za pomocą metody invalidate(). Jest to ważne, ponieważ invalidate () odświeża się tylko wtedy, gdy wątek jest bezczynny, np. na końcu pętla. Aby zaimplementować animację, musisz ją natychmiast narysować.)

  3. Następnie można zaimplementować pętlę, która rysuje ruchomy obraz na ekranie. Pętla musi zacząć od narysowania całego tła (ponieważ obszar roboczy nie jest automatycznie kasowany), a następnie narysować obraz w nowej pozycji na podstawie czasu, który minął. Na przykład, jeśli chcesz, aby animacja trwała 1 sekundę, wiesz, że jeśli minęło 200ms, widok powinien mieć tylko przesunięty 200/1000, czyli 1/5 drogi z pozycji wyjściowej do pozycji końcowej.

Możesz zobaczyć kilka przykładów tego, co mam na myśli w innych moich odpowiedziach na pytania dotyczące animacji: podstawowa odpowiedź na temat przydatności użycia SurfaceView oraz przykład pętli do użycia. Uwaga: drugie pytanie dotyczyło rotacji, dlatego niektóre trudności, o których mówiłem, nie będą dla Ciebie istotne. Powodzenia!

 9
Author: Steve Haley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:40

Miałem grupę widokową z dziećmi i przeciągałem widok na ekran od dołu - coś jak szuflada. Następnie puściłbym i gdyby górny margines viewgroup był w górnej połowie ekranu, animowałbym go na górę po zwolnieniu przez użytkownika dotyku.

Gdy to się stało, obrazy w dzieciach viewgroup były przycinane podczas animacji, ale następnie wyświetlane po animacji.

Problem: wysokość viewgroup to wrap_content. I rozwiązano ten problem, ustawiając wysokość na wartość, która rozciągała się od ekranu przed rozpoczęciem animacji.

 2
Author: Chris Sprague,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-23 20:07:55

Z android:translationX i android:translationY

<RelativeLayout
        android:translationX="-600dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">
 0
Author: Pablo Cegarra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 16:25:22