一个小的自定义的触摸控件,类似于联系人列表

这是一个自定义的触摸控件。这里做的触摸控件根据城市的首字母让列表选中相应的城市。下面放一张截图

写这个的心态就是,当时想要做这个功能。但是网上我找到的方法都很麻烦。所以干脆自己写了个控件。感觉挺简单的。

这里没有去完善它。只是实现了基本的功能。比如背景,文字颜色,并没有绘制。(直接代码里该比较痛快>o<)

mydemo.jpg

然后就是自定义控件的代码,我把注释写的比较详细。

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:代码全部贴上来。只有那个汉字转拼音的类。因为不是我写的就没有贴。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值