2013-07-29 4 views
17

Версия Android Spotify имеет уникальный эффект заголовка ListView при просмотре исполнителя. В основном изображение заголовка, похоже, поддерживает собственную скорость прокрутки, кроме фактического списка. Кто-нибудь знает, о чем я говорю? Если да, может кто-нибудь объяснить, как добиться этого эффекта?Spotify ListView image image image

Вот ссылка на видео с изложением эффекта заголовка изображения я имею в виду:

http://servestream.sourceforge.net/20130911_200347.mp4

+0

Добавьте изображение или загрузите видео о том, что вы говорите. Spotify имеет ограниченную совместимость с устройством. – Vikram

+0

Просто добавлено видео –

+1

Ссылка больше не доступна – Machado

ответ

21

Я сделал библиотеку с открытым исходным кодом, что дозировать только то, что вам нужно - https://github.com/nirhart/ParallaxScroll вы можете увидеть пример здесь - https://play.google.com/store/apps/details?id=com.nirhart.parallaxscrollexample

+0

Я новичок в android, поэтому извиняюсь за незнание вопроса, но как мне добавить эту библиотеку в мой существующий проект Android Studio? – Misha

+0

Я все еще использую eclipse, поэтому я не уверен, но, возможно, этот пост может помочь вам http://stackoverflow.com/questions/16588064/how-do-i-add-a-library-project-to-the-android-studio –

+0

I в итоге я вложил отдельные классы в свой проект. Спасибо. – Misha

0

Вы можете попробовать использовать FadingActionBar повторить путь Google Play Music обрабатывает это художник заголовки

+0

Извините, я не хочу, чтобы панель затухания исчезла. Мне просто нужно повлиять на заголовок ListView. –

+0

Ответ правильный. Библиотека делает то, что вы хотите, включая затухание панели действий. Если вам не нужен эффект затухания, используйте исходный код, в частности FadingActionBarHelper.java, и используйте нужные вам части. В частности, посмотрите на взаимодействия между заголовком, содержимым (в вашем случае списком), OnScrollListener и частями onNewScroll, которые обновляют высоту заголовка. –

+0

Эта библиотека достигает части того, что я хочу, но, о чем свидетельствует ваш ответ, не может быть легко повторным или сжатым способом. Говорить мне, чтобы прочитать исходный код и вырезать подозрительные части, которые я, возможно, не хочу, это не простой ответ, извините. –

28

Спасибо за размещение видео. Это эффект параллакса. Следующая библиотека может помочь вам достичь этого:

ParallaxScrollView: параллакс Scrollview, который принимает фон и передний план вида, в ParallexScrollView.

Link

Итак, я пошел вперед и изменил демо предложил по ссылке. Если это то, что вам нужно, сообщите мне, и я добавлю подробные сведения о тех изменениях, которые я сделал, чтобы это работало.

APK Link

Как получить это:

Если есть что-нибудь, кроме ListView в прокрутке части, то эффект был бы легко достичь. Поскольку контейнер, содержащий ListView, является расширенным ScrollView, все становится сложнее. Были сделаны следующие модификации:

В деятельности, раздувают следующую компоновку:

<couk.jenxsol.parallaxscrollview.views.ParallaxScrollView xmlns:tools="http://schemas.android.com/tools" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/scroll_view" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".DemoActivity" > 

<!-- Top Image: Here, the height is set to 300dp. You can set this in code --> 
<!-- depending on screen dimensions --> 

    <ImageView 
     android:id="@+id/iv" 
     android:layout_width="match_parent" 
     android:layout_height="300dp" 
     android:gravity="center" 
     android:scaleType="fitXY" 
     android:src="@drawable/image_to_use" /> 

<!-- Foreground --> 
<!-- You can place any of the items below as the foreground, --> 
<!-- but for most control, add the scroll view yourself. --> 

<!-- This is the area that will hold the ListView --> 
<!-- Also note that the LinearLayout's top margin will 
<!-- depend on ImageView's height. Here, there's an overalp of 100dp --> 
<!-- between the ImageView and the LinearLayout --> 
<!-- Reason: The first TextView(with a transparent background) inside the 
<!-- LinearLayout is displayed over the ImageView. --> 
<!-- So, the overlapping height should be equal to first TextView's height --> 
<!-- LinearLayout's top margin = ImageView's height - firstTextView's height --> 

<!-- AnotherView is an extended LinearLayout that I added to the library --> 

    <couk.jenxsol.parallaxscrollview.views.AnotherView 
     android:id="@+id/anotherView" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" > 

     <LinearLayout 
      android:id="@+id/llMainHolder" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_marginTop="200dp" 
      android:orientation="vertical" > 

      <TextView 
       android:id="@+id/tvTitle" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:background="@android:color/transparent" 
       android:gravity="center" 
       android:padding="@dimen/spacing" 
       android:text="Parallax Effect" 
       android:textColor="@android:color/white" 
       android:textSize="21sp" 
       tools:ignore="NewApi" /> 

      <!-- ListView --> 

      <LinearLayout 
       android:id="@+id/llMain" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" > 

       <ListView 
        android:id="@+id/lvMain" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:divider="@android:color/black" 
        android:dividerHeight="2px" > 

       </ListView> 

      </LinearLayout>    

     </LinearLayout> 

    </couk.jenxsol.parallaxscrollview.views.AnotherView> 

</couk.jenxsol.parallaxscrollview.views.ParallaxScrollView> 

код активность:

public class DemoActivity extends Activity { 

    private ParallaxScrollView mScrollView; 
    private ListView lvMain; 
    private LinearLayout llMain, llMainHolder; 
    private AnotherView anotherView; 
    private ImageView iv; 
    private TextView tvTitle; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 


     // Inflated layout 
     View mContent = getLayoutInflater().inflate(R.layout.activity_demo, null); 

     // Initialize components 

     mScrollView = (ParallaxScrollView) mContent.findViewById(R.id.scroll_view); 

     llMain = (LinearLayout) mContent.findViewById(R.id.llMain); 

     llMainHolder = (LinearLayout) mContent.findViewById(R.id.llMainHolder); 

     lvMain = (ListView) mContent.findViewById(R.id.lvMain); 

     iv = (ImageView) mContent.findViewById(R.id.iv); 

     tvTitle = (TextView) mContent.findViewById(R.id.tvTitle); 

     anotherView = (AnotherView) mContent.findViewById(R.id.anotherView); 

     String[] array = {"one", "two", "three", "four", "five", "six", "seven", "eight", 
      "nine", "ten", "evelen", "twelve", "thirteen", "fourteen"}; 

     ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.text, array); 

     lvMain.setAdapter(adapter);    

     // Set Content 
     setContentView(mContent); 

     lvMain.post(new Runnable() { 

      @Override 
      public void run() { 

       // Adjusts llMain's height to match ListView's height 
       setListViewHeight(lvMain, llMain); 

       // LayoutParams to set the top margin of LinearLayout holding 
       // the content. 
       // topMargin = iv.getHeight() - tvTitle.getHeight() 
       LinearLayout.LayoutParams p = 
         (LinearLayout.LayoutParams)llMainHolder.getLayoutParams(); 
       p.topMargin = iv.getHeight() - tvTitle.getHeight(); 
       llMainHolder.setLayoutParams(p); 
      } 
     }); 
    } 

    // Sets the ListView holder's height  
    public void setListViewHeight(ListView listView, LinearLayout llMain) { 
     ListAdapter listAdapter = listView.getAdapter(); 
     if (listAdapter == null) { 

      return; 
     } 

     int totalHeight = 0; 
     int firstHeight = 0; 
     int desiredWidth = MeasureSpec.makeMeasureSpec(
          listView.getWidth(), MeasureSpec.AT_MOST); 

     for (int i = 0; i < listAdapter.getCount(); i++) { 

      if (i == 0) { 
       View listItem = listAdapter.getView(i, null, listView); 
       listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED); 
       firstHeight = listItem.getMeasuredHeight(); 
     } 
      totalHeight += firstHeight; 
     } 

     LinearLayout.LayoutParams params = 
         (LinearLayout.LayoutParams)llMain.getLayoutParams(); 

     params.height = totalHeight + (listView.getDividerHeight() * 
               (listAdapter.getCount() - 1)); 
     llMain.setLayoutParams(params); 
     anotherView.requestLayout();  
    } 
} 

мнение, предоставляемая библиотекой, которая содержит контент (ObservableScrollView) проходит ScrollView. это вызывало проблемы с ListView, которые вы хотите отобразить. Я добавил AnotherView, который расширяет LinearLayout вместо:

public class AnotherView extends LinearLayout { 

private ScrollCallbacks mCallbacks; 

    static interface ScrollCallbacks { 
     public void onScrollChanged(int l, int t, int oldl, int oldt); 
    } 

    public void setCallbacks(ScrollCallbacks listener) { 
     mCallbacks = listener; 
    } 

    public AnotherView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     super.draw(canvas); 
    } 

    @Override 
    protected void onScrollChanged(int l, int t, int oldl, int oldt) { 
     super.onScrollChanged(l, t, oldl, oldt); 
     if (mCallbacks != null) { 
      mCallbacks.onScrollChanged(l, t, oldl, oldt); 
     } 
    } 

    @Override 
    public int computeVerticalScrollRange() { 
     return super.computeVerticalScrollRange(); 
    }    

} 

наконец: библиотека обеспечивает эффект параллакса. Эффект в вашем видео - эффект обратного параллакса. Чтобы получить желаемый результат, требуется небольшое изменение в ParallaxScrollView.onLayout(). Вместо final int scrollYCenterOffset = -mScrollView.getScrollY() используйте final int scrollYCenterOffset = mScrollView.getScrollY().

Измененная библиотека: Link.

Демо-проект: Link.

APK (пересмотренный/с ListView): Link.

+0

Это замечательно! Не могли бы вы объяснить, как добиться этого эффекта в вашем ответе, и я соглашусь с ним. Еще раз спасибо! –

+0

@WilliamSeemann Я обновил свой ответ. – Vikram

+0

@WilliamSeemann Можете ли вы привести мне пример (ссылку, html и т. Д.) Того, что WebView будет показывать? У меня не было большого опыта работы с WebView. Но, я дам это, если вы можете предоставить образец ссылки. – Vikram

0

Это просто делается так, предполагая, что у вас есть Scrollview, содержащий ImageView, что вы оба имеют ссылки на:

scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { 
     @Override 
     public void onScrollChanged() { 
        int top = scrollView.getScrollY(); // Increases when scrolling up^
        int newTop = (int) (top * .5f); 
        imageFrame.setTranslationY(newTop < 0 ? 0 : newTop); 

     } 
    }); 

Это будет прокручивать вверх ImageView с половинной скоростью по сравнению с остальной частью Scrollview, а также проверяет, что он никогда не прокручивает больше, чем следует (в прошлом 0)