android仿iphone滚轮控件显示效果

android仿iphone滚轮控件显示效果,供大家参考,具体内容如下

在论坛里看到的,自己弄个效果:

这个滚动的WheelView

 /*
 * Android Wheel Control.
 * https://code.google.com/p/android-wheel/
 *
 * Copyright 2010 Yuri Kanivets
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package kankan.wheel.widget; 

import java.util.LinkedList;
import java.util.List; 

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.Scroller; 

import com.shao.pwd.R; 

/**
 * Numeric wheel view.
 *
 * @author Yuri Kanivets
 */
public class WheelView extends View {
  /** Scrolling duration */
  private static final int SCROLLING_DURATION = 400; 

  /** Minimum delta for scrolling */
  private static final int MIN_DELTA_FOR_SCROLLING = 1; 

  /** Current value & label text color */
  private static final int VALUE_TEXT_COLOR = 0xF0000000; 

  /** Items text color */
  private static final int ITEMS_TEXT_COLOR = 0xFF000000; 

  /** Top and bottom shadows colors */
  private static final int[] SHADOWS_COLORS = new int[] { 0xFF111111,
      0x00AAAAAA, 0x00AAAAAA }; 

  /** Additional items height (is added to standard text item height) */
  private static final int ADDITIONAL_ITEM_HEIGHT = 15; 

  /** Text size */
  private static final int TEXT_SIZE = 24; 

  /** Top and bottom items offset (to hide that) */
  private static final int ITEM_OFFSET = TEXT_SIZE / 5; 

  /** Additional width for items layout */
  private static final int ADDITIONAL_ITEMS_SPACE = 10; 

  /** Label offset */
  private static final int LABEL_OFFSET = 8; 

  /** Left and right padding value */
  private static final int PADDING = 10; 

  /** Default count of visible items */
  private static final int DEF_VISIBLE_ITEMS = 5; 

  // Wheel Values
  private WheelAdapter adapter = null;
  private int currentItem = 0; 

  // Widths
  private int itemsWidth = 0;
  private int labelWidth = 0; 

  // Count of visible items
  private int visibleItems = DEF_VISIBLE_ITEMS; 

  // Item height
  private int itemHeight = 0; 

  // Text paints
  private TextPaint itemsPaint;
  private TextPaint valuePaint; 

  // Layouts
  private StaticLayout itemsLayout;
  private StaticLayout labelLayout;
  private StaticLayout valueLayout; 

  // Label & background
  private String label;
  private Drawable centerDrawable; 

  // Shadows drawables
  private GradientDrawable topShadow;
  private GradientDrawable bottomShadow; 

  // Scrolling
  private boolean isScrollingPerformed;
  private int scrollingOffset; 

  // Scrolling animation
  private GestureDetector gestureDetector;
  private Scroller scroller;
  private int lastScrollY; 

  // Cyclic
  boolean isCyclic = false; 

  // Listeners
  private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();
  private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>(); 

  /**
   * Constructor
   */
  public WheelView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initData(context);
  } 

  /**
   * Constructor
   */
  public WheelView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initData(context);
  } 

  /**
   * Constructor
   */
  public WheelView(Context context) {
    super(context);
    initData(context);
  } 

  /**
   * Initializes class data
   * @param context the context
   */
  private void initData(Context context) {
    gestureDetector = new GestureDetector(context, gestureListener);
    gestureDetector.setIsLongpressEnabled(false); 

    scroller = new Scroller(context);
  } 

  /**
   * Gets wheel adapter
   * @return the adapter
   */
  public WheelAdapter getAdapter() {
    return adapter;
  } 

  /**
   * Sets wheel adapter
   * @param adapter the new wheel adapter
   */
  public void setAdapter(WheelAdapter adapter) {
    this.adapter = adapter;
    invalidateLayouts();
    invalidate();
  } 

  /**
   * Set the the specified scrolling interpolator
   * @param interpolator the interpolator
   */
  public void setInterpolator(Interpolator interpolator) {
    scroller.forceFinished(true);
    scroller = new Scroller(getContext(), interpolator);
  } 

  /**
   * Gets count of visible items
   *
   * @return the count of visible items
   */
  public int getVisibleItems() {
    return visibleItems;
  } 

  /**
   * Sets count of visible items
   *
   * @param count
   *      the new count
   */
  public void setVisibleItems(int count) {
    visibleItems = count;
    invalidate();
  } 

  /**
   * Gets label
   *
   * @return the label
   */
  public String getLabel() {
    return label;
  } 

  /**
   * Sets label
   *
   * @param newLabel
   *      the label to set
   */
  public void setLabel(String newLabel) {
    if (label == null || !label.equals(newLabel)) {
      label = newLabel;
      labelLayout = null;
      invalidate();
    }
  } 

  /**
   * Adds wheel changing listener
   * @param listener the listener
   */
  public void addChangingListener(OnWheelChangedListener listener) {
    changingListeners.add(listener);
  } 

  /**
   * Removes wheel changing listener
   * @param listener the listener
   */
  public void removeChangingListener(OnWheelChangedListener listener) {
    changingListeners.remove(listener);
  } 

  /**
   * Notifies changing listeners
   * @param oldValue the old wheel value
   * @param newValue the new wheel value
   */
  protected void notifyChangingListeners(int oldValue, int newValue) {
    for (OnWheelChangedListener listener : changingListeners) {
      listener.onChanged(this, oldValue, newValue);
    }
  } 

  /**
   * Adds wheel scrolling listener
   * @param listener the listener
   */
  public void addScrollingListener(OnWheelScrollListener listener) {
    scrollingListeners.add(listener);
  } 

  /**
   * Removes wheel scrolling listener
   * @param listener the listener
   */
  public void removeScrollingListener(OnWheelScrollListener listener) {
    scrollingListeners.remove(listener);
  } 

  /**
   * Notifies listeners about starting scrolling
   */
  protected void notifyScrollingListenersAboutStart() {
    for (OnWheelScrollListener listener : scrollingListeners) {
      listener.onScrollingStarted(this);
    }
  } 

  /**
   * Notifies listeners about ending scrolling
   */
  protected void notifyScrollingListenersAboutEnd() {
    for (OnWheelScrollListener listener : scrollingListeners) {
      listener.onScrollingFinished(this);
    }
  } 

  /**
   * Gets current value
   *
   * @return the current value
   */
  public int getCurrentItem() {
    return currentItem;
  } 

  /**
   * Sets the current item. Does nothing when index is wrong.
   *
   * @param index the item index
   * @param animated the animation flag
   */
  public void setCurrentItem(int index, boolean animated) {
    if (adapter == null || adapter.getItemsCount() == 0) {
      return; // throw?
    }
    if (index < 0 || index >= adapter.getItemsCount()) {
      if (isCyclic) {
        while (index < 0) {
          index += adapter.getItemsCount();
        }
        index %= adapter.getItemsCount();
      } else{
        return; // throw?
      }
    }
    if (index != currentItem) {
      if (animated) {
        scroll(index - currentItem, SCROLLING_DURATION);
      } else {
        invalidateLayouts(); 

        int old = currentItem;
        currentItem = index; 

        notifyChangingListeners(old, currentItem); 

        invalidate();
      }
    }
  } 

  /**
   * Sets the current item w/o animation. Does nothing when index is wrong.
   *
   * @param index the item index
   */
  public void setCurrentItem(int index) {
    setCurrentItem(index, false);
  }   

  /**
   * Tests if wheel is cyclic. That means before the 1st item there is shown the last one
   * @return true if wheel is cyclic
   */
  public boolean isCyclic() {
    return isCyclic;
  } 

  /**
   * Set wheel cyclic flag
   * @param isCyclic the flag to set
   */
  public void setCyclic(boolean isCyclic) {
    this.isCyclic = isCyclic; 

    invalidate();
    invalidateLayouts();
  } 

  /**
   * Invalidates layouts
   */
  private void invalidateLayouts() {
    itemsLayout = null;
    valueLayout = null;
    scrollingOffset = 0;
  } 

  /**
   * Initializes resources
   */
  private void initResourcesIfNecessary() {
    if (itemsPaint == null) {
      itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
          | Paint.FAKE_BOLD_TEXT_FLAG);
      //itemsPaint.density = getResources().getDisplayMetrics().density;
      itemsPaint.setTextSize(TEXT_SIZE);
    } 

    if (valuePaint == null) {
      valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
          | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG);
      //valuePaint.density = getResources().getDisplayMetrics().density;
      valuePaint.setTextSize(TEXT_SIZE);
      valuePaint.setShadowLayer(0.1f, 0, 0.1f, 0xFFC0C0C0);
    } 

    if (centerDrawable == null) {
      centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val);
    } 

    if (topShadow == null) {
      topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);
    } 

    if (bottomShadow == null) {
      bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);
    } 

    setBackgroundResource(R.drawable.wheel_bg);
  } 

  /**
   * Calculates desired height for layout
   *
   * @param layout
   *      the source layout
   * @return the desired layout height
   */
  private int getDesiredHeight(Layout layout) {
    if (layout == null) {
      return 0;
    } 

    int desired = getItemHeight() * visibleItems - ITEM_OFFSET * 2
        - ADDITIONAL_ITEM_HEIGHT; 

    // Check against our minimum height
    desired = Math.max(desired, getSuggestedMinimumHeight()); 

    return desired;
  } 

  /**
   * Returns text item by index
   * @param index the item index
   * @return the item or null
   */
  private String getTextItem(int index) {
    if (adapter == null || adapter.getItemsCount() == 0) {
      return null;
    }
    int count = adapter.getItemsCount();
    if ((index < 0 || index >= count) && !isCyclic) {
      return null;
    } else {
      while (index < 0) {
        index = count + index;
      }
    } 

    index %= count;
    return adapter.getItem(index);
  } 

  /**
   * Builds text depending on current value
   *
   * @param useCurrentValue
   * @return the text
   */
  private String buildText(boolean useCurrentValue) {
    StringBuilder itemsText = new StringBuilder();
    int addItems = visibleItems / 2 + 1; 

    for (int i = currentItem - addItems; i <= currentItem + addItems; i++) {
      if (useCurrentValue || i != currentItem) {
        String text = getTextItem(i);
        if (text != null) {
          itemsText.append(text);
        }
      }
      if (i < currentItem + addItems) {
        itemsText.append("\n");
      }
    } 

    return itemsText.toString();
  } 

  /**
   * Returns the max item length that can be present
   * @return the max length
   */
  private int getMaxTextLength() {
    WheelAdapter adapter = getAdapter();
    if (adapter == null) {
      return 0;
    } 

    int adapterLength = adapter.getMaximumLength();
    if (adapterLength > 0) {
      return adapterLength;
    } 

    String maxText = null;
    int addItems = visibleItems / 2;
    for (int i = Math.max(currentItem - addItems, 0);
        i < Math.min(currentItem + visibleItems, adapter.getItemsCount()); i++) {
      String text = adapter.getItem(i);
      if (text != null && (maxText == null || maxText.length() < text.length())) {
        maxText = text;
      }
    } 

    return maxText != null ? maxText.length() : 0;
  } 

  /**
   * Returns height of wheel item
   * @return the item height
   */
  private int getItemHeight() {
    if (itemHeight != 0) {
      return itemHeight;
    } else if (itemsLayout != null && itemsLayout.getLineCount() > 2) {
      itemHeight = itemsLayout.getLineTop(2) - itemsLayout.getLineTop(1);
      return itemHeight;
    } 

    return getHeight() / visibleItems;
  } 

  /**
   * Calculates control width and creates text layouts
   * @param widthSize the input layout width
   * @param mode the layout mode
   * @return the calculated control width
   */
  private int calculateLayoutWidth(int widthSize, int mode) {
    initResourcesIfNecessary(); 

    int width = widthSize; 

    int maxLength = getMaxTextLength();
    if (maxLength > 0) {
      float textWidth = FloatMath.ceil(Layout.getDesiredWidth("0", itemsPaint));
      itemsWidth = (int) (maxLength * textWidth);
    } else {
      itemsWidth = 0;
    }
    itemsWidth += ADDITIONAL_ITEMS_SPACE; // make it some more 

    labelWidth = 0;
    if (label != null && label.length() > 0) {
      labelWidth = (int) FloatMath.ceil(Layout.getDesiredWidth(label, valuePaint));
    } 

    boolean recalculate = false;
    if (mode == MeasureSpec.EXACTLY) {
      width = widthSize;
      recalculate = true;
    } else {
      width = itemsWidth + labelWidth + 2 * PADDING;
      if (labelWidth > 0) {
        width += LABEL_OFFSET;
      } 

      // Check against our minimum width
      width = Math.max(width, getSuggestedMinimumWidth()); 

      if (mode == MeasureSpec.AT_MOST && widthSize < width) {
        width = widthSize;
        recalculate = true;
      }
    } 

    if (recalculate) {
      // recalculate width
      int pureWidth = width - LABEL_OFFSET - 2 * PADDING;
      if (pureWidth <= 0) {
        itemsWidth = labelWidth = 0;
      }
      if (labelWidth > 0) {
        double newWidthItems = (double) itemsWidth * pureWidth
            / (itemsWidth + labelWidth);
        itemsWidth = (int) newWidthItems;
        labelWidth = pureWidth - itemsWidth;
      } else {
        itemsWidth = pureWidth + LABEL_OFFSET; // no label
      }
    } 

    if (itemsWidth > 0) {
      createLayouts(itemsWidth, labelWidth);
    } 

    return width;
  } 

  /**
   * Creates layouts
   * @param widthItems width of items layout
   * @param widthLabel width of label layout
   */
  private void createLayouts(int widthItems, int widthLabel) {
    if (itemsLayout == null || itemsLayout.getWidth() > widthItems) {
      itemsLayout = new StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems,
          widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
          1, ADDITIONAL_ITEM_HEIGHT, false);
    } else {
      itemsLayout.increaseWidthTo(widthItems);
    } 

    if (!isScrollingPerformed && (valueLayout == null || valueLayout.getWidth() > widthItems)) {
      String text = getAdapter() != null ? getAdapter().getItem(currentItem) : null;
      valueLayout = new StaticLayout(text != null ? text : "",
          valuePaint, widthItems, widthLabel > 0 ?
              Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
              1, ADDITIONAL_ITEM_HEIGHT, false);
    } else if (isScrollingPerformed) {
      valueLayout = null;
    } else {
      valueLayout.increaseWidthTo(widthItems);
    } 

    if (widthLabel > 0) {
      if (labelLayout == null || labelLayout.getWidth() > widthLabel) {
        labelLayout = new StaticLayout(label, valuePaint,
            widthLabel, Layout.Alignment.ALIGN_NORMAL, 1,
            ADDITIONAL_ITEM_HEIGHT, false);
      } else {
        labelLayout.increaseWidthTo(widthLabel);
      }
    }
  } 

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec); 

    int width = calculateLayoutWidth(widthSize, widthMode); 

    int height;
    if (heightMode == MeasureSpec.EXACTLY) {
      height = heightSize;
    } else {
      height = getDesiredHeight(itemsLayout); 

      if (heightMode == MeasureSpec.AT_MOST) {
        height = Math.min(height, heightSize);
      }
    } 

    setMeasuredDimension(width, height);
  } 

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas); 

    if (itemsLayout == null) {
      if (itemsWidth == 0) {
        calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
      } else {
        createLayouts(itemsWidth, labelWidth);
      }
    } 

    if (itemsWidth > 0) {
      canvas.save();
      // Skip padding space and hide a part of top and bottom items
      canvas.translate(PADDING, -ITEM_OFFSET);
      drawItems(canvas);
      drawValue(canvas);
      canvas.restore();
    } 

    drawCenterRect(canvas);
    drawShadows(canvas);
  } 

  /**
   * Draws shadows on top and bottom of control
   * @param canvas the canvas for drawing
   */
  private void drawShadows(Canvas canvas) {
    topShadow.setBounds(0, 0, getWidth(), getHeight() / visibleItems);
    topShadow.draw(canvas); 

    bottomShadow.setBounds(0, getHeight() - getHeight() / visibleItems,
        getWidth(), getHeight());
    bottomShadow.draw(canvas);
  } 

  /**
   * Draws value and label layout
   * @param canvas the canvas for drawing
   */
  private void drawValue(Canvas canvas) {
    valuePaint.setColor(VALUE_TEXT_COLOR);
    valuePaint.drawableState = getDrawableState(); 

    Rect bounds = new Rect();
    itemsLayout.getLineBounds(visibleItems / 2, bounds); 

    // draw label
    if (labelLayout != null) {
      canvas.save();
      canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top);
      labelLayout.draw(canvas);
      canvas.restore();
    } 

    // draw current value
    if (valueLayout != null) {
      canvas.save();
      canvas.translate(0, bounds.top + scrollingOffset);
      valueLayout.draw(canvas);
      canvas.restore();
    }
  } 

  /**
   * Draws items
   * @param canvas the canvas for drawing
   */
  private void drawItems(Canvas canvas) {
    canvas.save(); 

    int top = itemsLayout.getLineTop(1);
    canvas.translate(0, - top + scrollingOffset); 

    itemsPaint.setColor(ITEMS_TEXT_COLOR);
    itemsPaint.drawableState = getDrawableState();
    itemsLayout.draw(canvas); 

    canvas.restore();
  } 

  /**
   * Draws rect for current value
   * @param canvas the canvas for drawing
   */
  private void drawCenterRect(Canvas canvas) {
    int center = getHeight() / 2;
    int offset = getItemHeight() / 2;
    centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);
    centerDrawable.draw(canvas);
  } 

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    WheelAdapter adapter = getAdapter();
    if (adapter == null) {
      return true;
    } 

      if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
      justify();
    }
    return true;
  } 

  /**
   * Scrolls the wheel
   * @param delta the scrolling value
   */
  private void doScroll(int delta) {
    scrollingOffset += delta; 

    int count = scrollingOffset / getItemHeight();
    int pos = currentItem - count;
    if (isCyclic && adapter.getItemsCount() > 0) {
      // fix position by rotating
      while (pos < 0) {
        pos += adapter.getItemsCount();
      }
      pos %= adapter.getItemsCount();
    } else if (isScrollingPerformed) {
      //
      if (pos < 0) {
        count = currentItem;
        pos = 0;
      } else if (pos >= adapter.getItemsCount()) {
        count = currentItem - adapter.getItemsCount() + 1;
        pos = adapter.getItemsCount() - 1;
      }
    } else {
      // fix position
      pos = Math.max(pos, 0);
      pos = Math.min(pos, adapter.getItemsCount() - 1);
    } 

    int offset = scrollingOffset;
    if (pos != currentItem) {
      setCurrentItem(pos, false);
    } else {
      invalidate();
    } 

    // update offset
    scrollingOffset = offset - count * getItemHeight();
    if (scrollingOffset > getHeight()) {
      scrollingOffset = scrollingOffset % getHeight() + getHeight();
    }
  } 

  // gesture listener
  private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
    public boolean onDown(MotionEvent e) {
      if (isScrollingPerformed) {
        scroller.forceFinished(true);
        clearMessages();
        return true;
      }
      return false;
    } 

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      startScrolling();
      doScroll((int)-distanceY);
      return true;
    } 

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      lastScrollY = currentItem * getItemHeight() + scrollingOffset;
      int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount() * getItemHeight();
      int minY = isCyclic ? -maxY : 0;
      scroller.fling(0, lastScrollY, 0, (int) -velocityY / 2, 0, 0, minY, maxY);
      setNextMessage(MESSAGE_SCROLL);
      return true;
    }
  }; 

  // Messages
  private final int MESSAGE_SCROLL = 0;
  private final int MESSAGE_JUSTIFY = 1; 

  /**
   * Set next message to queue. Clears queue before.
   *
   * @param message the message to set
   */
  private void setNextMessage(int message) {
    clearMessages();
    animationHandler.sendEmptyMessage(message);
  } 

  /**
   * Clears messages from queue
   */
  private void clearMessages() {
    animationHandler.removeMessages(MESSAGE_SCROLL);
    animationHandler.removeMessages(MESSAGE_JUSTIFY);
  } 

  // animation handler
  private Handler animationHandler = new Handler() {
    public void handleMessage(Message msg) {
      scroller.computeScrollOffset();
      int currY = scroller.getCurrY();
      int delta = lastScrollY - currY;
      lastScrollY = currY;
      if (delta != 0) {
        doScroll(delta);
      } 

      // scrolling is not finished when it comes to final Y
      // so, finish it manually
      if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
        currY = scroller.getFinalY();
        scroller.forceFinished(true);
      }
      if (!scroller.isFinished()) {
        animationHandler.sendEmptyMessage(msg.what);
      } else if (msg.what == MESSAGE_SCROLL) {
        justify();
      } else {
        finishScrolling();
      }
    }
  }; 

  /**
   * Justifies wheel
   */
  private void justify() {
    if (adapter == null) {
      return;
    } 

    lastScrollY = 0;
    int offset = scrollingOffset;
    int itemHeight = getItemHeight();
    boolean needToIncrease = offset > 0 ? currentItem < adapter.getItemsCount() : currentItem > 0;
    if ((isCyclic || needToIncrease) && Math.abs((float) offset) > (float) itemHeight / 2) {
      if (offset < 0)
        offset += itemHeight + MIN_DELTA_FOR_SCROLLING;
      else
        offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;
    }
    if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {
      scroller.startScroll(0, 0, 0, offset, SCROLLING_DURATION);
      setNextMessage(MESSAGE_JUSTIFY);
    } else {
      finishScrolling();
    }
  } 

  /**
   * Starts scrolling
   */
  private void startScrolling() {
    if (!isScrollingPerformed) {
      isScrollingPerformed = true;
      notifyScrollingListenersAboutStart();
    }
  } 

  /**
   * Finishes scrolling
   */
  void finishScrolling() {
    if (isScrollingPerformed) {
      notifyScrollingListenersAboutEnd();
      isScrollingPerformed = false;
    }
    invalidateLayouts();
    invalidate();
  } 

  /**
   * Scroll the wheel
   * @param itemsToSkip items to scroll
   * @param time scrolling duration
   */
  public void scroll(int itemsToScroll, int time) {
    scroller.forceFinished(true); 

    lastScrollY = scrollingOffset;
    int offset = itemsToScroll * getItemHeight(); 

    scroller.startScroll(0, lastScrollY, 0, offset - lastScrollY, time);
    setNextMessage(MESSAGE_SCROLL); 

    startScrolling();
  } 

}

主布局文件

 <?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:background="@drawable/layout_bg"
  android:layout_width="fill_parent"> 

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="24dp"
    android:layout_gravity="center_horizontal"
    android:textSize="20sp"
    android:textStyle="bold"
    android:text="Please enter PIN"/> 

  <LinearLayout
    android:layout_marginTop="24dp"
    android:layout_gravity="center_horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"> 

    <kankan.wheel.widget.WheelView android:id="@+id/passw_1"
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"/>
    <kankan.wheel.widget.WheelView android:id="@+id/passw_2"
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"/>
    <kankan.wheel.widget.WheelView android:id="@+id/passw_3"
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"/>
    <kankan.wheel.widget.WheelView android:id="@+id/passw_4"
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"/>
    <kankan.wheel.widget.WheelView android:id="@+id/passw_5"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"/>
    <kankan.wheel.widget.WheelView android:id="@+id/passw_6"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"/>
  </LinearLayout> 

  <TextView android:id="@+id/pwd_status"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="24dp"
    android:layout_gravity="center_horizontal"
    android:textSize="18sp"
    android:textColor="#FFF"
    android:text="Wrong PIN"/> 

  <Button android:id="@+id/btn_mix"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="12dp"
    android:textSize="18sp"
    android:text="  Mix "/> 

</LinearLayout>

适配器adapter

/*
 * Copyright 2010 Yuri Kanivets
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package kankan.wheel.widget; 

public interface WheelAdapter {
  /**
   * Gets items count
   * @return the count of wheel items
   */
  public int getItemsCount(); 

  /**
   * Gets a wheel item by index.
   *
   * @param index the item index
   * @return the wheel item text or null
   */
  public String getItem(int index); 

  /**
   * Gets maximum item length. It is used to determine the wheel width.
   * If -1 is returned there will be used the default wheel width.
   *
   * @return the maximum item length or -1
   */
  public int getMaximumLength();
}
/*
 * Copyright 2010 Yuri Kanivets
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package kankan.wheel.widget; 

/**
 * Numeric Wheel adapter.
 */
public class NumericWheelAdapter implements WheelAdapter { 

  /** The default min value */
  public static final int DEFAULT_MAX_VALUE = 9; 

  /** The default max value */
  private static final int DEFAULT_MIN_VALUE = 0; 

  // Values
  private int minValue;
  private int maxValue; 

  // format
  private String format; 

  /**
   * Default constructor
   */
  public NumericWheelAdapter() {
    this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);
  } 

  /**
   * Constructor
   * @param minValue the wheel min value
   * @param maxValue the wheel max value
   */
  public NumericWheelAdapter(int minValue, int maxValue) {
    this(minValue, maxValue, null);
  } 

  /**
   * Constructor
   * @param minValue the wheel min value
   * @param maxValue the wheel max value
   * @param format the format string
   */
  public NumericWheelAdapter(int minValue, int maxValue, String format) {
    this.minValue = minValue;
    this.maxValue = maxValue;
    this.format = format;
  } 

  @Override
  public String getItem(int index) {
    if (index >= 0 && index < getItemsCount()) {
      int value = minValue + index;
      return format != null ? String.format(format, value) : Integer.toString(value);
    }
    return null;
  } 

  @Override
  public int getItemsCount() {
    return maxValue - minValue + 1;
  } 

  @Override
  public int getMaximumLength() {
    int max = Math.max(Math.abs(maxValue), Math.abs(minValue));
    int maxLen = Integer.toString(max).length();
    if (minValue < 0) {
      maxLen++;
    }
    return maxLen;
  }
}

监听器Listener文件:

/*
 * Copyright 2010 Yuri Kanivets
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package kankan.wheel.widget; 

/**
 * Wheel scrolled listener interface.
 */
public interface OnWheelScrollListener {
  /**
   * Callback method to be invoked when scrolling started.
   * @param wheel the wheel view whose state has changed.
   */
  void onScrollingStarted(WheelView wheel); 

  /**
   * Callback method to be invoked when scrolling ended.
   * @param wheel the wheel view whose state has changed.
   */
  void onScrollingFinished(WheelView wheel);
}
/*
 * Copyright 2010 Yuri Kanivets
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package kankan.wheel.widget; 

/**
 * Wheel changed listener interface.
 * <p>The currentItemChanged() method is called whenever current wheel positions is changed:
 * <li> New Wheel position is set
 * <li> Wheel view is scrolled
 */
public interface OnWheelChangedListener {
 /**
  * Callback method to be invoked when current item changed
  * @param wheel the wheel view whose state has changed
  * @param oldValue the old value of current item
  * @param newValue the new value of current item
  */
 void onChanged(WheelView wheel, int oldValue, int newValue);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 使用Android造了个滚轮控件轮子示例

    关于 Android 实现 iOS 上的滚轮选择效果的控件,到 github 上一搜一大堆,之所以还要造这个轮子,目的是为了更好的学习自定义控件,这个控件是几个月前写的了,经过一段时间的完善,现在开源,顺便写这一篇简单的介绍文章. 效果如下,录屏软件看起来可能有点卡顿,具体可以下载源码运行: 自定义控件无非是 measure,draw,layout 三个过程,如果要支持手势动作,那么就再加上 touch . measure 测量过程比较简单,以文本大小所需要的尺寸,再加上 padding. @O

  • Android滚轮选择时间控件使用详解

    滚轮选择控件 Android自带的选择时间控件有点丑,往往产品和设计都比较嫌弃,希望做成ios一样的滚轮选择,下面是我在NumberPicker的基础上自定义的选择控件,效果如下: 原理 基于NumberPicker实现 动态填充数值 联动 接口监听回调 实现滚轮效果有github上mark比较多的WheelView,但是阅读源码发现数据是一次性填入的,选择时间的话,填入10年就是10*365=3650条数据,也就是new出三千多个TextView,想想都觉得恐怖,肯定是不行的,于是便想到用Nu

  • Android高仿IOS 滚轮选择控件

    最近根据项目需要,整理了一个相对比较全面的 WheelView 使用控件,借用之前看到的一句话来说,就是站在巨人肩膀上,进行了一些小调整. 这里先贴上效果图 一般常用的时间选择格式,,单项选择,以及城市联动,这里基本都可以满足了. 这里把 单项选择,和 日期时间选择 给提出到 Util 类中,代码如下: public class Util { /** * 时间选择回调 */ public interface TimerPickerCallBack { void onTimeSelect(Stri

  • Android 实现IOS 滚轮选择控件的实例(源码下载)

     Android 实现IOS 滚轮选择控件的实例 最近根据项目需要,整理了一个相对比较全面的 WheelView 使用控件,借用之前看到的一句话来说,就是站在巨人肩膀上,进行了一些小调整. 这里先贴上效果图 一般常用的时间选择格式,,单项选择,以及城市联动,这里基本都可以满足了. 这里把 单项选择,和 日期时间选择 给提出到 Util 类中,代码如下: public class Util { /** * 时间选择回调 */ public interface TimerPickerCallBack

  • 轻松实现可扩展自定义的Android滚轮时间选择控件

    项目需求中有个功能模块需要用到时间选择控件,但是android系统自带的太丑了,只能自己优化下,结合WheelView实现滚轮选择日期,好像网上也挺多这种文章的.但是适用范围还是不同,希望这个能够对需求相同的朋友有一定帮助.控件标题还有年月日时分秒这些可以自己控制是否显示,先来看效果. 1.有年月日时分的开始时间 2.只有年月日的结束时间 3.用于有时身份证到期的时间选择(分为勾选长期和直接选择时间两种,另外长期后面自己也可以进行扩展) 4.项目结构 5.直接贴代码,代码里面注释很详细 <spa

  • Android自定义实现循环滚轮控件WheelView

    首先呈上Android循环滚轮效果图: 现在很多地方都用到了滚轮布局WheelView,比如在选择生日的时候,风格类似系统提供的DatePickerDialog,开源的控件也有很多,不过大部分都是根据当前项目的需求绘制的界面,因此我就自己写了一款比较符合自己项目的WheelView. 首先这个控件有以下的需求:  1.能够循环滚动,当向上或者向下滑动到临界值的时候,则循环开始滚动  2.中间的一块有一块半透明的选择区,滑动结束时,哪一块在这个选择区,就选择这快.  3.继承自View进行绘制 然

  • android仿iphone滚轮控件显示效果

    android仿iphone滚轮控件显示效果,供大家参考,具体内容如下 在论坛里看到的,自己弄个效果: 这个滚动的WheelView /* * Android Wheel Control. * https://code.google.com/p/android-wheel/ * * Copyright 2010 Yuri Kanivets * * Licensed under the Apache License, Version 2.0 (the "License"); * you

  • android仿iphone主题效果的主菜单

    现在很多第三方Launcher((如360Launcher,GoLauncher)带有iphone主题,相信玩Android的人大都知道. 本例实现仿iphone主题的launcher的冰山一角.如下图: 从效果看,大概就能猜出用什么控件类(支持左右滑动的控件类+GridView),支持左右滑动的控件类,有很多了比如常用的Gallery,ViewPager,ViewFlipper,ViewFlow等等,本例自定义继承ViewGroup的.看过launcher源码的人应该都知道 有个Workspa

  • Android仿iphone自定义滚动选择器

    本文实例为大家分享了Android仿iphone自定义滚动选择器的具体代码,供大家参考,具体内容如下 一.多的不说,效果图,先走起 二.实例源码 (1)自定义控件 package com.pickerscrollview.views; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import android.annotation.Sup

  • Android之日期时间选择控件DatePicker和TimePicker实例

    这个月根据需求在项目中做了一个时间选择器,虽然没有用到Android原生的时间选择控件,但我羞愧地发现自己竟然从来没有用过这方面控件!趁现在有时间,赶紧查缺补漏,写一篇博客吧. (注:为了便于区分,本文将选择年月日的控件称为日期选择控件,将选择时分的控件称为时间选择控件.) 1.创建项目 新建一个项目,MainActivity的布局如下: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  • Android实现字母导航控件的示例代码

    目录 自定义属性 Measure测量 坐标计算 绘制 Touch事件处理 数据组装 显示效果 今天分享一个以前实现的通讯录字母导航控件,下面自定义一个类似通讯录的字母导航 View,可以知道需要自定义的几个要素,如绘制字母指示器.绘制文字.触摸监听.坐标计算等,自定义完成之后能够达到的功能如下: 完成列表数据与字母之间的相互联动; 支持布局文件属性配置; 在布局文件中能够配置相关属性,如字母颜色.字母字体大小.字母指示器颜色等属性. 主要内容如下: 自定义属性 Measure测量 坐标计算 绘制

  • java制作仿微信视频播放控件

    此控件继承自 SurfaceView,利用 MediaPlayer 播放视频. 小视频播放界面 MoviePlayerView.java import java.io.IOException; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListene

  • Android开发之TextView控件用法实例总结

    本文实例总结了Android开发之TextView控件用法.分享给大家供大家参考,具体如下: TextView控件可以向用户展现文本信息,我们可以设置该文本信息是否能编辑 1.TextView基本使用 在程序中创建TextView对象 在xml文件中布局使用 2.New Android Project-> Project name:TextView Build Target:Android 2.2 Application name:TextViewDemo Package name:com.b5

  • Android中findViewById获取控件返回为空问题怎么解决

    在Android程序中,有时候需要加载非原来activity中xml布局中的控件,来使Android程序的界面更加丰富. 我本身是在使用ViewFlipper中遇到的问题. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); inflater=(LayoutInflater)getSystemService(LAYO

  • android开发实现列表控件滚动位置精确保存和恢复的方法(推荐)

    Android开发经常要对列表的滚动位置进行保存和恢复,网上也有很多关于此功能的方法文章,但绝大多数都只能保存恢复到某一行,对于滚动到半行的情况不能精确的恢复.也有很多文章介绍了好几种方法,也说某些方法能够精确的控制,但实际上根本不能实现.还有些介绍了很多玄乎且非常复杂的方法,但也没看到能完整实现的代码. 经过一段时间的研究测试,下面的代码可以完美的实现列表滚动位置的精确保存和恢复,而且只是在原来记忆到行位置的基础上增加了2行代码而已. 具体见下面代码和注释: //保存位置: int posit

  • Android省市区三级联动控件使用方法实例讲解

    最近有需求需要实现省市区三级联动,但是发现之前的实现不够灵活,自己做了一些优化.为了方便以后使用,抽离出来放在了github上WheelView.同时把其核心库放在了JCenter中了,可以直接引用.也可以参考项目中的Demo进行引用 下面介绍一下如何使用 如果用的是AndroidStudio那么直接在build.gradle文件中添加依赖: dependencies { compile 'chuck.WheelItemView:library:1.0.1' } 成功引入库之后,可以在需要弹出省

随机推荐