wheelView多用于popupwindow用来滚动选择条目

github上的开源三方控件     spannableString   autofitTextView、PinnedSectionListView(固定标签)   SwipeListView(右滑删除) Titanic(loading动画) AutoHideListView(自动隐藏上下View的ListView)   pullToZoomScrollView(下拉图片会放大的、上滑会遮盖的ScrollView)  coverFlow(画廊效果)

大部分的三方控件都是类似的流程    用自己的布局  封装控件

package com.wangjie.wheelview;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView; import java.util.ArrayList;
import java.util.List; /**
* Author: wangjie
* Email: tiantian.china.2@gmail.com
* Date: 7/1/14.
*/
public class WheelView extends ScrollView {
public static final String TAG = WheelView.class.getSimpleName(); public static class OnWheelViewListener {
public void onSelected(int selectedIndex, String item) {
}
} private Context context;
// private ScrollView scrollView; private LinearLayout views; public WheelView(Context context) {
super(context);
init(context);
} public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} public WheelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
} // String[] items;
List<String> items; private List<String> getItems() {
return items;
} public void setItems(List<String> list) {
if (null == items) {
items = new ArrayList<String>();
}
items.clear();
items.addAll(list); // 前面和后面补全
for (int i = 0; i < offset; i++) {
items.add(0, "");
items.add("");
} initData(); } public static final int OFF_SET_DEFAULT = 1;
int offset = OFF_SET_DEFAULT; // 偏移量(需要在最前面和最后面补全) public int getOffset() {
return offset;
} public void setOffset(int offset) {
this.offset = offset;
} int displayItemCount; // 每页显示的数量 int selectedIndex = 1; private void init(Context context) {
this.context = context; // scrollView = ((ScrollView)this.getParent());
// Log.d(TAG, "scrollview: " + scrollView);
Log.d(TAG, "parent: " + this.getParent());
// this.setOrientation(VERTICAL);
this.setVerticalScrollBarEnabled(false); views = new LinearLayout(context);
views.setOrientation(LinearLayout.VERTICAL);
this.addView(views); scrollerTask = new Runnable() { public void run() { int newY = getScrollY();
if (initialY - newY == 0) { // stopped
final int remainder = initialY % itemHeight;
final int divided = initialY / itemHeight;
// Log.d(TAG, "initialY: " + initialY);
// Log.d(TAG, "remainder: " + remainder + ", divided: " + divided);
if (remainder == 0) {
selectedIndex = divided + offset; onSeletedCallBack();
} else {
if (remainder > itemHeight / 2) {
WheelView.this.post(new Runnable() {
@Override
public void run() {
WheelView.this.smoothScrollTo(0, initialY - remainder + itemHeight);
selectedIndex = divided + offset + 1;
onSeletedCallBack();
}
});
} else {
WheelView.this.post(new Runnable() {
@Override
public void run() {
WheelView.this.smoothScrollTo(0, initialY - remainder);
selectedIndex = divided + offset;
onSeletedCallBack();
}
});
} } } else {
initialY = getScrollY();
WheelView.this.postDelayed(scrollerTask, newCheck);
}
}
}; } int initialY; Runnable scrollerTask;
int newCheck = 50; public void startScrollerTask() { initialY = getScrollY();
this.postDelayed(scrollerTask, newCheck);
} private void initData() {
displayItemCount = offset * 2 + 1; for (String item : items) {
views.addView(createView(item));
} refreshItemView(0);
} int itemHeight = 0; private TextView createView(String item) {
TextView tv = new TextView(context);
tv.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tv.setSingleLine(true);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
tv.setText(item);
tv.setGravity(Gravity.CENTER);
int padding = dip2px(15);
tv.setPadding(padding, padding, padding, padding);
if (0 == itemHeight) {
itemHeight = getViewMeasuredHeight(tv);
Log.d(TAG, "itemHeight: " + itemHeight);
views.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight * displayItemCount));
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
this.setLayoutParams(new LinearLayout.LayoutParams(lp.width, itemHeight * displayItemCount));
}
return tv;
} @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt); // Log.d(TAG, "l: " + l + ", t: " + t + ", oldl: " + oldl + ", oldt: " + oldt); // try {
// Field field = ScrollView.class.getDeclaredField("mScroller");
// field.setAccessible(true);
// OverScroller mScroller = (OverScroller) field.get(this);
//
//
// if(mScroller.isFinished()){
// Log.d(TAG, "isFinished...");
// }
//
// } catch (Exception e) {
// e.printStackTrace();
// } refreshItemView(t); if (t > oldt) {
// Log.d(TAG, "向下滚动");
scrollDirection = SCROLL_DIRECTION_DOWN;
} else {
// Log.d(TAG, "向上滚动");
scrollDirection = SCROLL_DIRECTION_UP; } } private void refreshItemView(int y) {
int position = y / itemHeight + offset;
int remainder = y % itemHeight;
int divided = y / itemHeight; if (remainder == 0) {
position = divided + offset;
} else {
if (remainder > itemHeight / 2) {
position = divided + offset + 1;
} // if(remainder > itemHeight / 2){
// if(scrollDirection == SCROLL_DIRECTION_DOWN){
// position = divided + offset;
// Log.d(TAG, ">down...position: " + position);
// }else if(scrollDirection == SCROLL_DIRECTION_UP){
// position = divided + offset + 1;
// Log.d(TAG, ">up...position: " + position);
// }
// }else{
//// position = y / itemHeight + offset;
// if(scrollDirection == SCROLL_DIRECTION_DOWN){
// position = divided + offset;
// Log.d(TAG, "<down...position: " + position);
// }else if(scrollDirection == SCROLL_DIRECTION_UP){
// position = divided + offset + 1;
// Log.d(TAG, "<up...position: " + position);
// }
// }
// } // if(scrollDirection == SCROLL_DIRECTION_DOWN){
// position = divided + offset;
// }else if(scrollDirection == SCROLL_DIRECTION_UP){
// position = divided + offset + 1;
} int childSize = views.getChildCount();
for (int i = 0; i < childSize; i++) {
TextView itemView = (TextView) views.getChildAt(i);
if (null == itemView) {
return;
}
if (position == i) {
itemView.setTextColor(Color.parseColor("#0288ce"));
} else {
itemView.setTextColor(Color.parseColor("#bbbbbb"));
}
}
} /**
* 获取选中区域的边界
*/
int[] selectedAreaBorder; private int[] obtainSelectedAreaBorder() {
if (null == selectedAreaBorder) {
selectedAreaBorder = new int[2];
selectedAreaBorder[0] = itemHeight * offset;
selectedAreaBorder[1] = itemHeight * (offset + 1);
}
return selectedAreaBorder;
} private int scrollDirection = -1;
private static final int SCROLL_DIRECTION_UP = 0;
private static final int SCROLL_DIRECTION_DOWN = 1; Paint paint;
int viewWidth; @Override
public void setBackgroundDrawable(Drawable background) { if (viewWidth == 0) {
viewWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
Log.d(TAG, "viewWidth: " + viewWidth);
} if (null == paint) {
paint = new Paint();
paint.setColor(Color.parseColor("#83cde6"));
paint.setStrokeWidth(dip2px(1f));
} background = new Drawable() {
@Override
public void draw(Canvas canvas) {
canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[0], viewWidth * 5 / 6, obtainSelectedAreaBorder()[0], paint);
canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[1], viewWidth * 5 / 6, obtainSelectedAreaBorder()[1], paint);
} @Override
public void setAlpha(int alpha) { } @Override
public void setColorFilter(ColorFilter cf) { } @Override
public int getOpacity() {
return 0;
}
}; super.setBackgroundDrawable(background); } @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG, "w: " + w + ", h: " + h + ", oldw: " + oldw + ", oldh: " + oldh);
viewWidth = w;
setBackgroundDrawable(null);
} /**
* 选中回调
*/
private void onSeletedCallBack() {
if (null != onWheelViewListener) {
onWheelViewListener.onSelected(selectedIndex, items.get(selectedIndex));
} } public void setSeletion(int position) {
final int p = position;
selectedIndex = p + offset;
this.post(new Runnable() {
@Override
public void run() {
WheelView.this.smoothScrollTo(0, p * itemHeight);
}
}); } public String getSeletedItem() {
return items.get(selectedIndex);
} public int getSeletedIndex() {
return selectedIndex - offset;
} @Override
public void fling(int velocityY) {
super.fling(velocityY / 3);
} @Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) { startScrollerTask();
}
return super.onTouchEvent(ev);
} private OnWheelViewListener onWheelViewListener; public OnWheelViewListener getOnWheelViewListener() {
return onWheelViewListener;
} public void setOnWheelViewListener(OnWheelViewListener onWheelViewListener) {
this.onWheelViewListener = onWheelViewListener;
} private int dip2px(float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
} private int getViewMeasuredHeight(View view) {
int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
view.measure(width, expandSpec);
return view.getMeasuredHeight();
} }

WheelView

package com.wangjie.wheelview.sample;

import android.app.AlertDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.wangjie.wheelview.R;
import com.wangjie.wheelview.WheelView; import java.util.Arrays; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String[] PLANETS = new String[]{"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Uranus", "Neptune", "Pluto"}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); WheelView wva = (WheelView) findViewById(R.id.main_wv); wva.setOffset(1);
wva.setItems(Arrays.asList(PLANETS));
wva.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
Log.d(TAG, "selectedIndex: " + selectedIndex + ", item: " + item);
}
}); findViewById(R.id.main_show_dialog_btn).setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_show_dialog_btn:
View outerView = LayoutInflater.from(this).inflate(R.layout.wheel_view, null);
WheelView wv = (WheelView) outerView.findViewById(R.id.wheel_view_wv);
wv.setOffset(2);
wv.setItems(Arrays.asList(PLANETS));
wv.setSeletion(3);
wv.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
Log.d(TAG, "[Dialog]selectedIndex: " + selectedIndex + ", item: " + item);
}
}); new AlertDialog.Builder(this)
.setTitle("WheelView in Dialog")
.setView(outerView)
.setPositiveButton("OK", null)
.show(); break;
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
}
}

MAinActivity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
> <com.wangjie.wheelview.WheelView
android:id="@+id/main_wv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/> <Button
android:id="@+id/main_show_dialog_btn"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="show WheelView in Dialog!"
/> </LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"> <com.wangjie.wheelview.WheelView
android:id="@+id/wheel_view_wv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/> </LinearLayout>

wheelView.xml

注意: MainActivity中的list数据如果使用BaseAdapter的话 因为其中wheelView设置了offset所以取数据的时候需要减去offset值否则会报错list.get(position-offset);

效果如图

wheelView实现滚动选择 三方开源的封装控件 spannableString autofitTextView、PinnedSectionListView SwipeListView等等的更多相关文章

  1. 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)

    前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...

  2. 《Dotnet9》系列-开源C# WPF控件库3《HandyControl》强力推荐

    大家好,我是Dotnet9小编,一个从事dotnet开发8年+的程序员.我最近开始写dotnet分享文章,希望能让更多人看到dotnet的发展,了解更多dotnet技术,帮助dotnet程序员应用do ...

  3. 国内开源C# WPF控件库Panuon.UI.Silver推荐

    国内优秀的WPF开源控件库,Panuon.UI的优化版本.一个漂亮的.使用样式与附加属性的WPF UI控件库,值得向大家推荐使用与学习. 今天站长(Dotnet9,站长网址:https://dotne ...

  4. 国内开源C# WPF控件库Panuon.UI.Silver强力推荐

    国内优秀的WPF开源控件库,Panuon.UI的优化版本.一个漂亮的.使用样式与附加属性的WPF UI控件库,值得向大家推荐使用与学习. 今天站长(Dotnet9,站长网址:https://dotne ...

  5. 《Dotnet9》系列-开源C# WPF控件库2《Panuon.UI.Silver》强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  6. (四)开源C# WPF控件库《AduSkin – UI》

    微信公众号:[Dotnet9的博客],网站:[Dotnet9],问题或建议:[请网站留言], 如果对您有所帮助:[欢迎赞赏]. 开源C# WPF控件库系列: (一)开源C# WPF控件库<Mat ...

  7. 《Dotnet9》系列-开源C# Winform控件库1《HZHControls》强力推荐

    大家好,我是Dotnet9小编,一个从事dotnet开发8年+的程序员.我最近在写dotnet分享文章,希望能让更多人看到dotnet的发展,了解更多dotnet技术,帮助dotnet程序员应用dot ...

  8. 《Dotnet9》系列-开源C# WPF控件库1《MaterialDesignInXAML》强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  9. 一步一步学Silverlight 2系列(8):使用样式封装控件观感

    述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

随机推荐

  1. Graylog日志管理系统---搜索查询方法使用简介

    Elasticsearch 是一个基于 Lucene 构建的开源.分布式.提供 RESTful 接口的全文搜索引擎 一.Search页面的各位置功能介绍: 1.日志搜索的时间范围 为了使用方便,预设有 ...

  2. openwrt手动wifi设成client模式[笔记]

    说明:刚刷好的OPENWRT,默认是不带luci-web管理的,所以得手工SSH或TELNET上去改WIFI模式,以便通过WIFI连到现有的ROUTER去下载安装luci...: root@OpenW ...

  3. 29.Junit测试框架.md

    目录 作用 使用 单个对象的测试 有步骤的测试 注意 作用 用于简化测试,可以对方法,类,包等范围测试 使用 单个对象的测试 在需要测试的方法上加注解@Test,选中方法,运行里选择junit执行 同 ...

  4. linux下json工具jq

    1.查看json文件 [root@VM-1-10-11 f46c19f56252a74a46fd30026001e62cc5ecadd04bc9a80c47f6fd5f9dc0586b]# pwd / ...

  5. python小数据池概念以及具体范围

    =   赋值符号:        ==  比较值是否相等:   is  比较,比较的是内存地址      ID(内容) 数字,字符串的小数据池 小数据池现象产生的原因,作用: 为了节省内存空间. &l ...

  6. Linux查看进程运行的完整路径方法

    通过ps及top命令查看进程信息时,只能查到相对路径,查不到的进程的详细信息,如绝对路径等.这时,我们需要通过以下的方法来查看进程的详细信息: Linux在启动一个进程时,系统会在/proc下创建一个 ...

  7. 文字在线转图片二维码的公用API接口

    在线生成网址二维码的API接口: 1.百度网盘(可使用https)       http://pan.baidu.com/share/qrcode?w=150&h=150&url=ht ...

  8. Html写作规范

    HTML是描述网页结构的超文本标记语言,HTML规范能够使HTML代码风格保持一致,使得HTML更容易理解和维护. 整体结构 用编辑器快捷键一键搞定 <!DOCTYPE html>---- ...

  9. scrapy爬虫的编写步骤

    scrapy的步骤: a.编写item,爬取的各个属性 b.编写spider,name 要和 scrapy crawl xxspider一致,里面编写parse的信息,就是xpath获取item的各个 ...

  10. xlrd使用

    import xlrd //导入模块filename='路径/文件名' //文件路径.名称python读取excel中单元格的内容返回的有5种类型,即ctype:0. empty(空的),1 stri ...