Android - Как позиционировать просмотр вне экрана? - PullRequest
58 голосов
/ 31 марта 2010

Я пытаюсь анимировать простой ImageView в своем приложении, и я хочу, чтобы он скользил снизу экрана и находился в исходном положении, когда верхние 50 пикселей вида находятся за верхом экрана (например окончательная позиция ImageView должна быть -50px в X). Я попытался использовать AbsoluteLayout, чтобы сделать это, но это фактически обрезает верхние 50 пикселей в ImageView, так что верхние 50 пикселей никогда не отображаются. Мне нужно, чтобы верхние 50 пикселей в ImageView были видимыми / визуализированными во время его анимации, а затем просто сделать его немного за кадром. Надеюсь, я объяснил это достаточно хорошо.

Вот то, что я сейчас использую в качестве макета и анимации слайда (в настоящее время это не отображает верхние 50 пикселей в ImageView):

Компоновка:

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

Анимация:

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

Заранее спасибо.

Ответы [ 6 ]

33 голосов
/ 02 апреля 2010

Я нашел решение, которое должно быть легко реализовано. Он включает в себя изменение макета и действия, надувающие макет ... см. Ниже:

Активность (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));
    }
}

Новый LinearLayout (CustomLinearLayout.java):

* +1007 *

Макет (/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>

Ресурс (/res/values/constants.xml):

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

Анимация (/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>

Теперь программа делает именно то, что мне нужно. Весь макет начинается с экрана внизу, скользит за 1 секунду и останавливается, когда верх макета на самом деле находится в 50 пикселях от верхней части экрана (т.е. LL.getTop() = -50), а нижняя часть макета находится на нижняя часть экрана (т.е. LL.getBottom() = 530 = 480 + 50).

30 голосов
/ 19 апреля 2012

Для позиционирования моего взгляда вне экрана я использовал следующий код:

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

Этот код будет позиционировать myView вне экрана по количествуOffscreen, что в данном случае выводит 80% экрана за пределы экрана, оставляя на экране только 20%.

Не используйте метод layout () напрямую - Android будет делать последующие вызовы, чтобы сделать ваш просмотр недействительным по случайным причинам, и только сообщения layoutParams сохраняются при вызовах недействительности. Если вам интересно, посмотрите строки 904–912 этого файла , чтобы понять, почему вам нужно изменить layoutParams.

29 голосов
/ 13 мая 2015

Вместо этого мы можем просто дать отрицательные значения layout_margin (сверху / слева / справа / снизу) Например: если вы хотите, чтобы ваш вид был выключен в верхней части экрана, вы можете указать

android:layout_marginTop="-40dp"
9 голосов
/ 01 апреля 2010

Это легко сделать, если вы перейдете к использованию Canvas; те поддерживают рисование с экрана без каких-либо проблем. Однако это будет сложнее реализовать. Вам нужно реализовать пользовательский View и написать собственную анимацию в коде. По сути, это сводится к простой обработке 2D-графики, а не к представлениям с использованием встроенной XML-анимации. Возможно, есть способ сделать это с XML, но я гораздо лучше знаком с холстами. Очень хорошее место, чтобы увидеть, как это обрабатывается в коде, - это пример игры Lunar Lander, который поставляется с SDK.

Примерно вам нужно выполнить следующие шаги:

  1. Поместите пользовательское представление в файл XML, используя что-то вроде <your.package.AnimatingView>, установив его размер для fill-parent.

  2. Затем определите класс AnimatingView, который extends SurfaceView and implements SurfaceHolder.Callback. (Это дает вам доступ к чертежу Canvas немедленно, а не с помощью метода invalidate(). Это важно, потому что invalidate () обновляется только тогда, когда поток простаивает, например, в конце цикла. Чтобы реализовать анимацию, Вы должны немедленно нарисовать его.)

  3. Затем вы можете реализовать цикл, который рисует ваше движущееся изображение по экрану. Цикл должен начаться с рисования всего фона (потому что холст не стирается автоматически), а затем нарисовать изображение в его новом положении на основе прошедшего времени. Например, если вы хотите, чтобы анимация занимала 1 секунду, то вы знаете, что если прошло 200 мс, представление должно было сместиться только на 200/1000 или 1/5 пути от его начальной позиции до конечной позиции. .

Вы можете увидеть некоторые примеры того, что я имею в виду в других моих ответах на вопросы об анимации: базовый ответ о полезности использования SurfaceView и пример цикла для использования . Примечание: второй вопрос касался ротации, и поэтому некоторые из трудностей, о которых я говорил, не будут иметь отношения к вам. Удачи!

3 голосов
/ 20 сентября 2018

С android:translationX и 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">
2 голосов
/ 24 января 2014

У меня была группа с детьми, и я перетаскивал вид на экран снизу - вроде ящика. Затем я отпустил бы, и если бы верхнее поле в группе просмотра находилось в верхней половине экрана, я бы анимировал его наверх после того, как пользователь выпустил касание.

Когда это происходило, изображения в дочерних группах просмотра обрезались во время анимации, но затем отображались после анимации.

Проблема: высота группы просмотра была wrap_content. Я решил эту проблему, установив значение высоты, которое растягивалось за пределы экрана до начала анимации.

...