The Android version of Spotify has a unique ListView header effect when viewing an artist. Basically the header image appears to maintain it\'s own scrolling speed apart fro
Thanks for posting the video. This is a parallax effect. The following library can help you achieve it:
ParallaxScrollView: A Parallax ScrollView which takes a background and foreground view, in the ParallexScrollView.
Link
So, I went ahead and modified the demo offered on the link. If this is what you are after, let me know and I'll add details on the modifications I did to get this working.
APK Link
How to get this:
If there was anything but a ListView in the scrollable part, the effect would have been easy to achieve. Because the container holding the ListView is an extended ScrollView, things get complicated. The following modifications were made:
In the activity, inflate the following layout:
Activity code:
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 adapter = new ArrayAdapter(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();
}
}
The view provided by the library that holds the content (ObservableScrollView) extends a ScrollView. this was causing problems with the ListView that you want to display. I addedAnotherView that extends a LinearLayout instead:
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();
}
}
At last: the library provides the parallax effect. The effect in your video is a reverse parallax effect. To get the desired result, a small change is required in ParallaxScrollView.onLayout(). In place of final int scrollYCenterOffset = -mScrollView.getScrollY(), use final int scrollYCenterOffset = mScrollView.getScrollY().
Modified library: Link.
Demo project: Link.
APK (revised / with ListView): Link.