这是一个自定义的触摸控件。这里做的触摸控件根据城市的首字母让列表选中相应的城市。下面放一张截图
写这个的心态就是,当时想要做这个功能。但是网上我找到的方法都很麻烦。所以干脆自己写了个控件。感觉挺简单的。
这里没有去完善它。只是实现了基本的功能。比如背景,文字颜色,并没有绘制。(直接代码里该比较痛快>o<)
然后就是自定义控件的代码,我把注释写的比较详细。
package com.example.testcityselect;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
private GestureDetector gestureDetector;// 这个是用于引用手势探测器的
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mContext = (MainActivity) context;// 将context对象强制转换为mContext对象
gestureDetector = new GestureDetector(context, new GestureListener(),
null, true);// 初始化手势探测器,其中第二个参数是本类中定义的类,继承自
}
private MainActivity mContext;// 由于例子中调用了MainActivity中定义方法,(用以修改居中的TextView的值)所以需要这个引用
private int oneHeight;// 指每一个字母的高度
public MyView(Context context) {
super(context);// 调用父类View类默认构造方法
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Log.e("tag", getHeight()+"/"+getWidth());
Paint paint = new Paint();
// paint.setARGB(200, 180, 170, 45);
paint.setTextSize(20);// 设置字体的大小
// canvas.drawColor(Color.CYAN);
Paint bgPaint = new Paint();
bgPaint.setARGB(255, 255, 255, 255);// 绘制背景的颜色
Rect rect=new Rect();
getLocalVisibleRect(rect);
canvas.drawRect(rect, bgPaint);
oneHeight=(rect.bottom-rect.top)/26;
paint.setARGB(255, 0, 0, 0);// 设置字母的颜色
paint.setTextSize(20);
for (int i = 1; i < 27; i++) {
canvas.drawText((char) (i + 64) + "", rect.left+getWidth()/2-10, oneHeight * i, paint);
}// 利用for循环绘制字母
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
boolean retVal = false;
retVal = gestureDetector.onTouchEvent(event);
return retVal;
}// 覆盖这个方法是为了让组件响应触摸事件
/**
* public void onUpDown(int i) { mContext.setText((char) i + "");
* invalidate(); } 之前的想法是应该分为向上向下滑动,但后来直接使用一个for循环,即记录下当前手指所在高度。
**/
private class GestureListener extends
GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
// Toast.makeText(context, e.getX() + "," + e.getY(),
// Toast.LENGTH_SHORT).show();
int i = 1;
for (; i < 26; i++) {
if (e.getY() < (oneHeight) * i) {
break;
}
}// 这里。手指按下后执行这个for循环,找出最接近的字母
mContext.setText(i + 64);
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
// x = e1.getX() + droid.getWidth();
// y = e1.getY();
for (int i = 1; i < 27; i++) {
if (e2.getY() < (oneHeight) * i) {
mContext.setText(i + 64);
break;
}
}// 这里。只要手指移动都会改变str的值
return true;
}
}
}
之后是布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testcityselect.MainActivity" >
<TextView
android:id="@+id/tv_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
android:layout_centerInParent="true"
android:textSize="50dp"/>
<ListView
android:id="@+id/lv_city_select"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<com.example.testcityselect.MyView android:layout_width="20dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_margin="5dp"
/>
</RelativeLayout>
然后主Activity,这里没有什么特殊的。城市的信息是放在一个本地json文件中的
排序是根据汉字的首字母对应的字母的int值。这里根据汉字获取拼音是用了网路上分享的一个工具HanziToPinyin.就不贴出来了,
(貌似HanziToPinyin有个bug重庆获取到的首字母是Z)
然后这里的setText方法。是在上面的自定义控件中调用的。主要功能是设置中间的文本框显示字母,和让列表选中相应的字母列
然后还有个timer类。是让textview隐藏的。就是实现不点击控件的状态。textview隐藏
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ArrayAdapter<String> cityAdapter;
private ListView lvContactList;
private List<CityInfo> cityList;
private TextView tv_hello;
private MyView view;
private Map<Integer, Integer> cityMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvContactList = (ListView) findViewById(R.id.lv_city_select);
cityList = new ArrayList<CityInfo>();
cityMap = new HashMap<Integer, Integer>();
HanziToPinyin tools = new HanziToPinyin(true);
InputStreamReader inputStream = new InputStreamReader(getResources()
.openRawResource(R.raw.json_simple_name));
BufferedReader reader = new BufferedReader(inputStream);
try {
String json = reader.readLine();
reader.close();
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObj = jsonArray.getJSONObject(i);
String city = jsonObj.getString("city");
String s = tools.get(jsonObj.getString("city")).get(0).target;
int temp = s.charAt(0);
// data.add(temp+"");
cityList.add(new CityInfo(temp, city));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Collections.sort(cityList);
cityAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_expandable_list_item_1);
cityAdapter.add((char) cityList.get(0).getNum() + "");
cityAdapter.add(cityList.get(0).getCity());
cityMap.put(cityList.get(0).getNum(), 0);
for (int i = 1, count = 1; i < cityList.size(); i++) {
if (cityList.get(i).getNum() != cityList.get(i - 1).getNum()) {
cityAdapter.add((char) cityList.get(i).getNum() + "");
cityMap.put(cityList.get(i).getNum(), ++count);
}
cityAdapter.add(cityList.get(i).getCity());
count++;
}
lvContactList.setAdapter(cityAdapter);
tv_hello = (TextView) findViewById(R.id.tv_hello);
tv_hello.setVisibility(View.GONE);
lvContactList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
String str = cityAdapter.getItem(position);
if (str.length() > 1)
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT)
.show();
}
});
}
public void setText(int i) {
tv_hello.setText((char) i + "");
Integer a = cityMap.get(i);
if (a != null)
lvContactList.setSelection(a);
tv_hello.setVisibility(View.VISIBLE);
final Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.sendEmptyMessage(0);
timer.cancel();
}
}, 2000);
}
Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub.
if(msg.what==0)
tv_hello.setVisibility(View.GONE);
return false;
}
});
}
实体类覆盖了用于排序的方法
package com.example.testcityselect;
public class CityInfo implements Comparable<CityInfo> {
int num;
String city;
public CityInfo(int num, String city) {
super();
this.num = num;
this.city = city;
}
@Override
public int compareTo(CityInfo another) {
// TODO Auto-generated method stub
if (this.num < another.num) {
return -1;
} else if (this.num > another.num) {
return 1;
}
return 0;
}
public int getNum() {
return num;
}
public String getCity() {
return city;
}
}
ps:代码全部贴上来。只有那个汉字转拼音的类。因为不是我写的就没有贴。