content: package com.cjj.mousepaint.contral.control;
  
  import android.animation.Animator;
  import android.animation.AnimatorSet;
  import android.content.Context;
  import android.os.Handler;
  import android.os.Vibrator;
  import android.util.AttributeSet;
  import android.view.MotionEvent;
  import android.view.View;
  import android.widget.HorizontalScrollView;
  import android.widget.LinearLayout;
  
  
  import com.cjj.mousepaint.R;
  import com.cjj.mousepaint.contral.control.RhythmAdapter;
  import com.cjj.mousepaint.utils.AnimatorUtils;
  import com.cjj.mousepaint.utils.AppUtils;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Timer;
  import java.util.TimerTask;
  
  /**
   * User: shine
   * Date: 2014-12-12
   * Time: 16:48
   * Description:
   */
  public class RhythmLayout extends HorizontalScrollView {
  
  
      private Context mContext;
  
      private RhythmAdapter mAdapter;
  
      private Handler mHandler;
  
      private ShiftMonitorTimer mTimer;
  
      private IRhythmItemListener mListener;
  
  
      private LinearLayout mLinearLayout;
  
      private float mItemWidth;
  
      private int mMaxTranslationHeight;
  
      private int mIntervalHeight;
  
      private int mCurrentItemPosition;
  
      private int mEdgeSizeForShiftRhythm;
  
      private int mScreenWidth;
  
      private long mFingerDownTime;
  
      private int mScrollStartDelayTime;
  
      private int mLastDisplayItemPosition;
  
      public RhythmLayout(Context context) {
          this(context, null);
      }
  
      public RhythmLayout(Context context, AttributeSet attrs) {
          super(context, attrs);
          mContext = context;
          init();
      }
  
      private void init() {
          mScreenWidth = AppUtils.getScreenDisplayMetrics(mContext).widthPixels;
          mItemWidth = mScreenWidth / 7;
          mMaxTranslationHeight = (int) mItemWidth;
          mIntervalHeight = (mMaxTranslationHeight / 6);
          mEdgeSizeForShiftRhythm = getResources().getDimensionPixelSize(R.dimen.rhythm_edge_size_for_shift);
          mCurrentItemPosition = -1;
          mLastDisplayItemPosition = -1;
          mScrollStartDelayTime = 0;
          mFingerDownTime = 0;
          mHandler = new Handler();
          mTimer = new ShiftMonitorTimer();
          mTimer.startMonitor();
      }
  
      public void setAdapter(RhythmAdapter adapter) {
          this.mAdapter = adapter;
          if (mLinearLayout == null) {
              mLinearLayout = (LinearLayout) getChildAt(0);
          }
          mAdapter.setItemWidth(mItemWidth);
          for (int i = 0; i < this.mAdapter.getCount(); i++) {
              mLinearLayout.addView(mAdapter.getView(i, null, null));
          }
      }
  
  
      public void invalidateData() {
          int childCount = this.mLinearLayout.getChildCount();
          if (childCount < this.mAdapter.getCount())
              for (int i = childCount; i < this.mAdapter.getCount(); i++)
                  this.mLinearLayout.addView(this.mAdapter.getView(i, null, null));
      }
  
  
      @Override
      public boolean dispatchTouchEvent(MotionEvent ev) {
          switch (ev.getAction()) {
              case MotionEvent.ACTION_MOVE:
                  mTimer.monitorTouchPosition(ev.getX(), ev.getY());
                  updateItemHeight(ev.getX());
                  break;
              case MotionEvent.ACTION_DOWN:
                  mTimer.monitorTouchPosition(ev.getX(), ev.getY());
                  mFingerDownTime = System.currentTimeMillis();
                  updateItemHeight(ev.getX());
                  if (mListener != null)
                      mListener.onStartSwipe();
                  break;
              case MotionEvent.ACTION_UP:
                  actionUp();
                  break;
          }
  
          return true;
      }
  
  
      private void actionUp() {
          mTimer.monitorTouchPosition(-1.0F, -1.0F);
          if (mCurrentItemPosition < 0) {
              return;
          }
          int firstPosition = getFirstVisibleItemPosition();
          int lastPosition = firstPosition + mCurrentItemPosition;
          final List viewList = getVisibleViews();
          int size = viewList.size();
          if (size > mCurrentItemPosition) {
              viewList.remove(mCurrentItemPosition);
          }
          if (firstPosition - 1 >= 0) {
              viewList.add(mLinearLayout.getChildAt(firstPosition - 1));
          }
          if (lastPosition + 1 <= mLinearLayout.getChildCount()) {
              viewList.add(mLinearLayout.getChildAt(lastPosition + 1));
          }
          this.mHandler.postDelayed(new Runnable() {
              public void run() {
                  for (int i = 0; i < viewList.size(); i++) {
                      View downView = (View) viewList.get(i);
                      shootDownItem(downView, true);
                  }
              }
          }, 200L);
          if (mListener != null)
              mListener.onSelected(lastPosition);
          mCurrentItemPosition = -1;
          vibrate(20L);
      }
  
      private void updateItemHeight(float scrollX) {
          List viewList = getVisibleViews();
          int position = (int) (scrollX / mItemWidth);
          if (position == mCurrentItemPosition || position >= mLinearLayout.getChildCount())
              return;
          mCurrentItemPosition = position;
          makeItems(position, viewList);
      }
  
  
      private void makeItems(int fingerPosition, List<View> viewList) {
          if (fingerPosition >= viewList.size()) {
              return;
          }
          int size = viewList.size();
          for (int i = 0; i < size; i++) {
  
              int translationY = Math.min(Math.max(Math.abs(fingerPosition - i) * mIntervalHeight, 10), mMaxTranslationHeight);
              updateItemHeightAnimator(viewList.get(i), translationY);
          }
  
      }
  
  
      private List<View> getVisibleViews() {
          ArrayList arrayList = new ArrayList();
          if (mLinearLayout == null)
              return arrayList;
          int firstPosition = getFirstVisibleItemPosition();
          int lastPosition = firstPosition + 7;
          if (mLinearLayout.getChildCount() < 7) {
              lastPosition = mLinearLayout.getChildCount();
          }
          for (int i = firstPosition; i < lastPosition; i++)
              arrayList.add(mLinearLayout.getChildAt(i));
          return arrayList;
      }
  
  
      private List<View> getVisibleViews(boolean isForward, boolean isBackward) {
          ArrayList viewList = new ArrayList();
          if (this.mLinearLayout == null)
              return viewList;
          int firstPosition = getFirstVisibleItemPosition();
          int lastPosition = firstPosition + 7;
          if (mLinearLayout.getChildCount() < 7) {
              lastPosition = mLinearLayout.getChildCount();
          }
          if ((isForward) && (firstPosition > 0))
              firstPosition--;
          if ((isBackward) && (lastPosition < mLinearLayout.getChildCount()))
              lastPosition++;
          for (int i = firstPosition; i < lastPosition; i++)
              viewList.add(mLinearLayout.getChildAt(i));
  
          return viewList;
      }
  
  
      public int getFirstVisibleItemPosition() {
          if (mLinearLayout == null) {
              return 0;
          }
          int size = mLinearLayout.getChildCount();
          for (int i = 0; i < size; i++) {
              View view = mLinearLayout.getChildAt(i);
              if (getScrollX() < view.getX() + mItemWidth / 2.0F)
                  return i;
          }
          return 0;
      }
  
  
      class ShiftMonitorTimer extends Timer {
          private TimerTask timerTask;
          private boolean canShift = false;
          private float x;
          private float y;
  
          void monitorTouchPosition(float x, float y) {
              this.x = x;
              this.y = y;
              if ((x < 0.0F) || ((x > mEdgeSizeForShiftRhythm) && (x < mScreenWidth - mEdgeSizeForShiftRhythm)) || (y < 0.0F)) {
                  mFingerDownTime = System.currentTimeMillis();
                  this.canShift = false;
              } else {
                  this.canShift = true;
              }
          }
  
          void startMonitor() {
              if (this.timerTask == null) {
                  timerTask = new TimerTask() {
                      @Override
                      public void run() {
                          long duration = System.currentTimeMillis() - mFingerDownTime;
                          if (canShift && duration > 1000) {
                              int firstPosition = getFirstVisibleItemPosition();
                              int toPosition = 0;
                              boolean isForward = false;
                              boolean isBackward = false;
                              final List<View> localList;
                              if (x <= mEdgeSizeForShiftRhythm && x >= 0.0F) {
                                  if (firstPosition - 1 >= 0) {
                                      mCurrentItemPosition = 0;
                                      toPosition = firstPosition - 1;
                                      isForward = true;
                                      isBackward = false;
  
                                  }
                              } else if (x > mScreenWidth - mEdgeSizeForShiftRhythm) {
                                  if (getSize() >= 1 + (firstPosition + 7)) {
                                      mCurrentItemPosition = 7;
                                      toPosition = firstPosition + 1;
                                      isForward = false;
                                      isBackward = true;
                                  }
                              }
                              if (isForward || isBackward) {
                                  localList = getVisibleViews(isForward, isBackward);
                                  final int finalToPosition = toPosition;
                                  mHandler.post(new Runnable() {
                                      public void run() {
                                          makeItems(mCurrentItemPosition, localList);
                                          scrollToPosition(finalToPosition, 200, 0, true);
                                          vibrate(10L);
                                      }
                                  });
                              }
  
                          }
  
                      }
                  };
              }
              schedule(timerTask, 200L, 250L);
  
          }
      }
  
      public int getSize() {
          if (mLinearLayout == null) {
              return 0;
          }
          return mLinearLayout.getChildCount();
      }
  
      public View getItemView(int position) {
          return mLinearLayout.getChildAt(position);
      }
  
  
      public Animator scrollToPosition(int position, int duration, int startDelay, boolean isStart) {
          int viewX = (int) getItemView(position).getX();
          return smoothScrollX(viewX, duration, startDelay, isStart);
      }
  
  
      public Animator scrollToPosition(int position, int startDelay, boolean isStart) {
          int viewX = (int) getItemView(position).getX();
          return smoothScrollX(viewX, 300, startDelay, isStart);
      }
  
      private Animator smoothScrollX(int position, int duration, int startDelay, boolean isStart) {
          return AnimatorUtils.moveScrollViewToX(this, position, duration, startDelay, isStart);
      }
  
  
      private void updateItemHeightAnimator(View view, int translationY) {
          if (view != null)
              AnimatorUtils.showUpAndDownBounce(view, translationY, 180, true, true);
      }
  
  
  
      public Animator shootDownItem(int viewPosition, boolean isStart) {
          if ((viewPosition >= 0) && (mLinearLayout != null) && (getSize() > viewPosition))
              return shootDownItem(getItemView(viewPosition), isStart);
          return null;
      }
  
      public Animator shootDownItem(View view, boolean isStart) {
          if (view != null)
              return AnimatorUtils.showUpAndDownBounce(view, mMaxTranslationHeight, 350, isStart, true);
          return null;
      }
  
  
      public Animator bounceUpItem(int viewPosition, boolean isStart) {
          if (viewPosition >= 0)
              return bounceUpItem(getItemView(viewPosition), isStart);
          return null;
      }
  
      public Animator bounceUpItem(View view, boolean isStart) {
          if (view != null)
              return AnimatorUtils.showUpAndDownBounce(view, 10, 350, isStart, true);
          return null;
      }
  
  
      private void vibrate(long miss) {
          ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(new long[]{0L, miss}, -1);
      }
  
  
      public void setRhythmListener(IRhythmItemListener listener) {
          this.mListener = listener;
      }
  
      public void setScrollRhythmStartDelayTime(int scrollStartDelayTime) {
          this.mScrollStartDelayTime = scrollStartDelayTime;
      }
  
      public float getRhythmItemWidth() {
          return mItemWidth;
      }
  
  
      public void showRhythmAtPosition(int position) {
          if (this.mLastDisplayItemPosition == position)
              return;
          Animator scrollAnimator;
          Animator bounceUpAnimator;
          Animator shootDownAnimator;
  
          if ((this.mLastDisplayItemPosition < 0) || (mAdapter.getCount() <= 7) || (position <= 3)) {
              scrollAnimator = scrollToPosition(0, mScrollStartDelayTime, false);
          } else if (mAdapter.getCount() - position <= 3) {
              scrollAnimator = scrollToPosition(mAdapter.getCount() - 7, mScrollStartDelayTime, false);
          } else {
              scrollAnimator = scrollToPosition(position - 3, mScrollStartDelayTime, false);
          }
          bounceUpAnimator = bounceUpItem(position, false);
          shootDownAnimator = shootDownItem(mLastDisplayItemPosition, false);
          AnimatorSet animatorSet1 = new AnimatorSet();
          if (bounceUpAnimator != null) {
              animatorSet1.playTogether(bounceUpAnimator);
          }
          if (shootDownAnimator != null) {
              animatorSet1.playTogether(shootDownAnimator);
          }
          AnimatorSet animatorSet2 = new AnimatorSet();
          animatorSet2.playSequentially(new Animator[]{scrollAnimator, animatorSet1});
          animatorSet2.start();
          mLastDisplayItemPosition = position;
      }
  
  }
  