/*
********************************************************************************
* Copyright (c) 2012 Samsung Electronics, Inc.
* All rights reserved.
*
* This software is a confidential and proprietary information of Samsung
* Electronics, Inc. ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the terms
* of the license agreement you entered into with Samsung Electronics.
********************************************************************************
*/
package com.sprc.circlelauncher.view;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.TextView;
import com.sprc.circlelauncher.BuildConfig;
import com.sprc.circlelauncher.R;
public class CircleListView extends ListView implements OnScrollListener {
private static final String TAG = CircleListView.class.getSimpleName();
private static final boolean DEBUG = BuildConfig.DEBUG && false;
private static final int DEFAULT_SCROLL_DURATION = 200;
public static final int DEFAULT_SELECTION = Integer.MAX_VALUE / 2;
private boolean mIsForceCentering;
private ViewModifier mViewModifier;
private final CenterRunnable mCenterRunnable = new CenterRunnable();
private int mScrollDuration = DEFAULT_SCROLL_DURATION;
private OnItemCenteredListener mOnItemCenteredListener;
public CircleListView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setOnScrollListener(this);
setOverscrollFooter(null);
setOverscrollHeader(null);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setSelection(DEFAULT_SELECTION);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mViewModifier != null) {
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
View v = getChildAt(i);
mViewModifier.applyToView(v, this);
}
}
}
/**
* Sets the current {@link ViewModifier} for this list.
*
* @param modifier
* implementation of the {@link ViewModifier} class
*
* @see ViewModifier
*/
public void setViewModifier(ViewModifier modifier) {
mViewModifier = modifier;
}
/**
* Sets the smooth scroll duration.
*
* @param duration
* the number of milliseconds the scrolling animation will take
*/
public void setScrollDuration(int duration) {
mScrollDuration = duration;
}
/**
* Sets the listener object that will be notified when the list centers on an item.
*
* @param listener
* the {@link OnItemCenteredListener} implementation
*/
public void setOnItemCenteredListener(OnItemCenteredListener listener) {
mOnItemCenteredListener = listener;
}
/**
* Smoothly scrolls the {@link CircleListView} so the {@link View} v is in the middle.
*
* @param v
* the {@link View} that should be in the center after the scroll
* @param scrollDuration
* how long will the scroll take
*/
public void smoothScrollToView(View v) {
final float y = v.getY() + v.getHeight() * 0.5f;
final float halfHeight = getHeight() * 0.5f;
final int distance = (int) (y - halfHeight);
smoothScrollBy(distance, mScrollDuration);
}
@Override
public void setOnScrollListener(OnScrollListener l) {
throw new UnsupportedOperationException();
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
if (!mIsForceCentering) {
// Start centering the view
mIsForceCentering = true;
final View childView = findViewAtCenter();
if (childView != null) {
if (DEBUG) {
TextView tv = (TextView) childView.findViewById(R.id.label_app_name);
Log.d(TAG, "Application in center: " + tv.getText().toString());
}
if (mOnItemCenteredListener != null) {
mOnItemCenteredListener.onItemCentered(childView);
}
mCenterRunnable.setView(childView);
ViewCompat.postOnAnimation(this, mCenterRunnable);
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
removeCallbacks(mCenterRunnable);
mIsForceCentering = false;
return super.onTouchEvent(ev);
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
/**
* Finds a View located at the specified point.
*
* @param x
* x-coordinate of the point
* @param y
* y-coordinate of the point
* @return {@link View} located at (x, y) or <code>null</code> if not found
*/
public View findViewAt(int x, int y) {
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final View v = getChildAt(i);
final int x0 = v.getLeft();
final int y0 = v.getTop();
final int x1 = v.getWidth() - x0;
final int y1 = v.getHeight() + y0;
if (x >= x0 && x <= x1 && y >= y0 && y <= y1) {
return v;
}
}
return null;
}
/**
* Finds a {@link View} located in the center of the {@link CircleListView}.
*
* @return the {@link View} at the center of the {@link CircleListView}
*/
public View findViewAtCenter() {
return findViewAt(0, getHeight() / 2);
}
public class CenterRunnable implements Runnable {
private View mView;
public void setView(View v) {
mView = v;
}
public void run() {
smoothScrollToView(mView);
mIsForceCentering = true;
}
}
/**
* Handles the event occurring when the list centers on an item.
*
* @see CircleListView#setOnItemCenteredListener(OnItemCenteredListener)
*/
public interface OnItemCenteredListener {
public void onItemCentered(View v);
}
}