/** * Constructor that is called when inflating a view from XML. This is called when a view is being * constructed from an XML file, supplying attributes that were specified in the XML file. This * version uses a default style of 0, so the only attribute values applied are those in the * Context's Theme and the given AttributeSet. * * <p>The method onFinishInflate() will be called after all children have been added. * * @param context The Context the view is running in, through which it can access the current * theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. */ public TableFixHeaders(Context context, AttributeSet attrs) { super(context, attrs); this.headView = null; this.rowViewList = new ArrayList<View>(); this.columnViewList = new ArrayList<View>(); this.bodyViewTable = new ArrayList<List<View>>(); this.needRelayout = true; this.shadows = new ImageView[4]; this.shadows[0] = new ImageView(context); this.shadows[0].setImageResource(R.drawable.shadow_left); this.shadows[1] = new ImageView(context); this.shadows[1].setImageResource(R.drawable.shadow_top); this.shadows[2] = new ImageView(context); this.shadows[2].setImageResource(R.drawable.shadow_right); this.shadows[3] = new ImageView(context); this.shadows[3].setImageResource(R.drawable.shadow_bottom); // this.lineView = new View(context); // this.lineView.setTag(R.id.tag_row, -2); this.shadowSize = getResources().getDimensionPixelSize(R.dimen.shadow_size); this.flinger = new Flinger(context); final ViewConfiguration configuration = ViewConfiguration.get(context); this.touchSlop = configuration.getScaledTouchSlop(); this.minimumVelocity = configuration.getScaledMinimumFlingVelocity(); this.maximumVelocity = configuration.getScaledMaximumFlingVelocity(); }
private void postLongClickRunnable() { myLongClickPerformed = false; myPendingPress = false; if (myPendingLongClickRunnable == null) { myPendingLongClickRunnable = new LongClickRunnable(); } postDelayed(myPendingLongClickRunnable, 2 * ViewConfiguration.getLongPressTimeout()); }
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (myKeyUnderTracking != -1) { if (myKeyUnderTracking == keyCode) { final boolean longPress = System.currentTimeMillis() > myTrackingStartTime + ViewConfiguration.getLongPressTimeout(); ZLApplication.Instance().runActionByKey(keyCode, longPress); } myKeyUnderTracking = -1; return true; } else { final ZLKeyBindings bindings = ZLApplication.Instance().keyBindings(); return bindings.hasBinding(keyCode, false) || bindings.hasBinding(keyCode, true); } }
@Override public boolean onTouch(View v, MotionEvent event) { // detector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); downX = event.getX(); break; case MotionEvent.ACTION_UP: v.performClick(); break; case MotionEvent.ACTION_MOVE: // 是否已滚动到无法继续滑动 boolean isEnable = false; // 手指move的像素值超过系统判定判定滚动的最小临界值,避免手指抖动造成chart图抖动 if (Math.abs(event.getX() - downX) > ViewConfiguration.get(context).getScaledTouchSlop()) { int transValue = (int) (event.getX() - startX); if (axesData.size() > 1) { int max = axesData.get(axesData.size() - 1).X; int min = axesData.get(0).X; int maxLimit = width - rightPadding - POINT_PADDING; int minLimit = leftPadding + yTextWidth + POINT_PADDING; if (min + transValue > minLimit) { // 滑动以后左边界判断 if (min < minLimit) { transValue = minLimit - min; isEnable = true; } else { transValue = 0; if (loadMore != null) { loadMore.onLoad(); } } } else { isEnable = true; } if (max + transValue < maxLimit) { // 滑动后右边界判断 if (max > maxLimit) { transValue = maxLimit - max; isEnable = true; } else { transValue = 0; } } else { isEnable = true; } Log.d("min", min + ""); Log.d("minLimit", minLimit + ""); Log.d("transValue", transValue + ""); if (isEnable) { startX = event.getX(); refreshChart(transValue); } } } break; default: break; } return true; }
// 惯性线程 class FlingThread extends Thread { // 初始速度 private int velocity; private static final float INFLEXION = 0.35f; // 取得系统摩擦系数 private float mFlingFriction = ViewConfiguration.getScrollFriction(); private float mPhysicalCoeff; private final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); // 计算出惯性总时间 private double mDuration; // 刷新频率 private int timeInterval = 1000 / 60; // 单位MS // 当前惯性耗时 private int spendTime; public FlingThread(float velocityX) { velocity = (int) velocityX; final float ppi = context.getResources().getDisplayMetrics().density * 160.0f; mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2) * 39.37f // inch/meter * ppi * 0.84f; // look and feel tuning } @Override public void run() { isInertia = true; boolean isEnable = false; if (velocity != 0) { mDuration = getSplineFlingDuration(velocity); // 不断循环直到惯性时间到达或者用户点击屏幕中断滑动 while (mDuration >= spendTime && isInertia) { // 每时间间隔内惯性滑动的距离 int space = (int) (velocity + (2 * spendTime / timeInterval + 1) * -velocity / mDuration * timeInterval / 2) * timeInterval / 1000; try { if (axesData.size() > 1) { int max = axesData.get(axesData.size() - 1).X; int min = axesData.get(0).X; int maxLimit = width - rightPadding - 20; int minLimit = leftPadding + yTextWidth + 20; if (min + space > minLimit) { // 滑动以后左边界判断 if (min < minLimit) { isEnable = true; } else { space = 0; refreshChart(space); return; } } else { isEnable = true; } if (max + space < maxLimit) { // 滑动后右边界判断 if (max > maxLimit) { isEnable = true; } else { space = 0; refreshChart(space); return; } } else { isEnable = true; } if (isEnable) { refreshChart(space); } } else { return; } spendTime += timeInterval; sleep(timeInterval); isScrollEnd = true; } catch (InterruptedException e) { e.printStackTrace(); } } } } // 根据速度计算加速度 private double getSplineDeceleration(int velocity) { return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * 2 * mPhysicalCoeff)); } /* Returns the duration, expressed in milliseconds */ private int getSplineFlingDuration(int velocity) { final double l = getSplineDeceleration(velocity); final double decelMinusOne = DECELERATION_RATE - 1.0; return (int) (1000.0 * Math.exp(l / decelMinusOne)); } }
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); final ZLView view = ZLApplication.Instance().getCurrentView(); switch (event.getAction()) { case MotionEvent.ACTION_UP: if (myPendingDoubleTap) { view.onFingerDoubleTap(x, y); } else if (myLongClickPerformed) { view.onFingerReleaseAfterLongPress(x, y); } else { if (myPendingLongClickRunnable != null) { removeCallbacks(myPendingLongClickRunnable); myPendingLongClickRunnable = null; } if (myPendingPress) { if (view.isDoubleTapSupported()) { if (myPendingShortClickRunnable == null) { myPendingShortClickRunnable = new ShortClickRunnable(); } postDelayed(myPendingShortClickRunnable, ViewConfiguration.getDoubleTapTimeout()); } else { view.onFingerSingleTap(x, y); } } else { view.onFingerRelease(x, y); } } myPendingDoubleTap = false; myPendingPress = false; myScreenIsTouched = false; break; case MotionEvent.ACTION_DOWN: if (myPendingShortClickRunnable != null) { removeCallbacks(myPendingShortClickRunnable); myPendingShortClickRunnable = null; myPendingDoubleTap = true; } else { postLongClickRunnable(); myPendingPress = true; } myScreenIsTouched = true; myPressedX = x; myPressedY = y; break; case MotionEvent.ACTION_MOVE: { final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); final boolean isAMove = Math.abs(myPressedX - x) > slop || Math.abs(myPressedY - y) > slop; if (isAMove) { myPendingDoubleTap = false; } if (myLongClickPerformed) { view.onFingerMoveAfterLongPress(x, y); } else { if (myPendingPress) { if (isAMove) { if (myPendingShortClickRunnable != null) { removeCallbacks(myPendingShortClickRunnable); myPendingShortClickRunnable = null; } if (myPendingLongClickRunnable != null) { removeCallbacks(myPendingLongClickRunnable); } view.onFingerPress(myPressedX, myPressedY); myPendingPress = false; } } if (!myPendingPress) { view.onFingerMove(x, y); } } break; } } return true; }