Android 打造可下拉的EditText--DropEditText

android的默认Spinner只能下拉选择内容,而不能选择,有时候我们想提供给用户更加人性化的UI,既可以通过下拉选择,也可以通过EditText输入,是要定义两个组件吗? 这样并不适合我们的设计要求。

那么, 我们就自己写一个这样的组件吧——DropEditText。

一、思路

1、DropEditText并不是一个Spinner,也不是一个EditText。

2、这里的解决方式是,组合以个EditText和一个ImageView,点击ImageView弹出一个PopupWindow达到下拉的效果。

二、问题

1、组合EditText和ImageView,而又不能让用户看出这是一个组合。

2、PopupWindow弹出的位置怎么控制。

3、如何做到当点击PopupWindow上的选项,向EditText填充对应的内容。


三、效果

再开始代码之前,先看看预想的效果吧,有了目标才好code


通过效果图可以看出,DropEditText还算比较灵活的,可以设置下拉的模式:跟随上面和包裹内容。


四、解决问题

再回头看看我们的问题。

第一个问题很好解决,相信很多人都可以轻松的解决。做法是用一个LinearLayout包裹EditText和ImageView,同时设置LinearLayout的背景为我们定义的shape,同时取消掉EditText默认的背景。

[html] view
plain
copy

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="wrap_content"
  4. android:orientation="horizontal"
  5. android:background="@drawable/edit_bg_shape" >
  6. <EditText
  7. android:id="@+id/dropview_edit"
  8. android:layout_width="0dip"
  9. android:layout_weight="1"
  10. android:layout_height="wrap_content"
  11. style="?android:attr/textViewStyle"
  12. android:background="@null"
  13. android:height="40dip" />
  14. <ImageView
  15. android:id="@+id/dropview_image"
  16. android:layout_width="wrap_content"
  17. android:layout_height="match_parent"
  18. android:layout_gravity="center_vertical"
  19. android:scaleType="fitXY"
  20. android:layout_marginTop="2dip"
  21. android:layout_marginBottom="2dip"
  22. android:paddingRight="2dip" />
  23. </LinearLayout>

第二个问题,控制PopupWindow的弹出的位置,很明显我们需要它显示在EditText上下面,sdk给我们提供了一个很好的方法:

[html] view
plain
copy

  1. PopupWindow.showAsDropDown(anchor, xoff, yoff)

参数1:以哪个view为目标弹出

参数2:x偏移量

参数3:y的偏移量

第二个问题就这么轻松的解决了。


第三个问题,我想到了用ListView做,用ListView做可以很方便的取item,但是有一个问题:ListView默认是占满横向的屏幕的,但这也不是问题,我们可以重写ListView的onMeasure方法改变它的测量机制。


五、上代码

先来看看重写的ListView吧,做的工作就是重写onMeasure方法,使它的宽度可变,还提供了一个方法可以设置ListView的宽度:

[java] view
plain
copy

  1. public class WrapListView extends ListView {
  2. private int mWidth = 0;
  3. public WrapListView(Context context, AttributeSet attrs) {
  4. this(context, attrs, 0);
  5. }
  6. public WrapListView(Context context, AttributeSet attrs, int defStyle) {
  7. super(context, attrs, defStyle);
  8. }
  9. // 重写onMeasure方法 解决默认横向占满屏幕问题
  10. @Override
  11. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  12. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  13. int height = getMeasuredHeight();
  14. // measureChildren(widthMeasureSpec, heightMeasureSpec);
  15. for(int i=0;i<getChildCount();i++) {
  16. int childWidth = getChildAt(i).getMeasuredWidth();
  17. mWidth = Math.max(mWidth, childWidth);
  18. }
  19. setMeasuredDimension(mWidth, height);
  20. }
  21. /**
  22. * 设置宽度,如果不设置,则默认包裹内容
  23. * @param width 宽度
  24. */
  25. protected void setListWidth(int width) {
  26. mWidth = width;
  27. }
  28. }

重点在14~25行,首先我们调用了一下父类的onMeasure方法,为的就是利用ListView默认的测量机制获取总高度。在第17行我们获取了测量后的高度,接下来就是一个for循环,取出每一个item,并获取他的高度。mWidth的值就是子item中最宽的那个item的宽度(当然在下面我们提供的方法中可以手动修改mWidth的值)。

自定义的setListWidth方法可以手动设置ListView的宽度,按说,我们改变了width的值,应该requestLayout()一下让ListView重走一下测量流程才对,但这里没有提供。答案就是:ListView默认是不显示的,只有在点击了drop图标后才会出现,也就是setListWidth()永远会走在onMeasure前面,可能到这里会有点晕,看完下面的代码后就会清楚了。

再来看看DropEditText吧,这个View是组合了EditText和ImageView,内置了一个PopupWindow,让组件用起来更见方便。

[java] view
plain
copy

  1. public class DropEditText extends FrameLayout implements View.OnClickListener, OnItemClickListener {
  2. private EditText mEditText;  // 输入框
  3. private ImageView mDropImage; // 右边的图片按钮
  4. private PopupWindow mPopup; // 点击图片弹出popupwindow
  5. private WrapListView mPopView; // popupwindow的布局
  6. private int mDrawableLeft;
  7. private int mDropMode; // flower_parent or wrap_content
  8. private String mHit;
  9. public DropEditText(Context context, AttributeSet attrs) {
  10. this(context, attrs, 0);
  11. }
  12. public DropEditText(Context context, AttributeSet attrs, int defStyle) {
  13. super(context, attrs, defStyle);
  14. LayoutInflater.from(context).inflate(R.layout.edit_layout, this);
  15. mPopView = (WrapListView) LayoutInflater.from(context).inflate(R.layout.pop_view, null);
  16. TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DropEditText, defStyle, 0);
  17. mDrawableLeft = ta.getResourceId(R.styleable.DropEditText_drawableRight, R.drawable.ic_launcher);
  18. mDropMode = ta.getInt(R.styleable.DropEditText_dropMode, 0);
  19. mHit = ta.getString(R.styleable.DropEditText_hint);
  20. ta.recycle();
  21. }
  22. @Override
  23. protected void onFinishInflate() {
  24. super.onFinishInflate();
  25. mEditText = (EditText) findViewById(R.id.dropview_edit);
  26. mDropImage = (ImageView) findViewById(R.id.dropview_image);
  27. mEditText.setSelectAllOnFocus(true);
  28. mDropImage.setImageResource(mDrawableLeft);
  29. if(!TextUtils.isEmpty(mHit)) {
  30. mEditText.setHint(mHit);
  31. }
  32. mDropImage.setOnClickListener(this);
  33. mPopView.setOnItemClickListener(this);
  34. }
  35. @Override
  36. protected void onLayout(boolean changed, int left, int top, int right,
  37. int bottom) {
  38. super.onLayout(changed, left, top, right, bottom);
  39. // 如果布局发生改
  40. // 并且dropMode是flower_parent
  41. // 则设置ListView的宽度
  42. if(changed && 0 == mDropMode) {
  43. mPopView.setListWidth(getMeasuredWidth());
  44. }
  45. }
  46. /**
  47. * 设置Adapter
  48. * @param adapter ListView的Adapter
  49. */
  50. public void setAdapter(BaseAdapter adapter) {
  51. mPopView.setAdapter(adapter);
  52. mPopup = new PopupWindow(mPopView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  53. mPopup.setBackgroundDrawable(new ColorDrawable(color.transparent));
  54. mPopup.setFocusable(true); // 让popwin获取焦点
  55. }
  56. /**
  57. * 获取输入框内的内容
  58. * @return String content
  59. */
  60. public String getText() {
  61. return mEditText.getText().toString();
  62. }
  63. @Override
  64. public void onClick(View v) {
  65. if(v.getId() == R.id.dropview_image) {
  66. if(mPopup.isShowing()) {
  67. mPopup.dismiss();
  68. return;
  69. }
  70. mPopup.showAsDropDown(this, 0, 5);
  71. }
  72. }
  73. @Override
  74. public void onItemClick(AdapterView<?> parent, View view, int position,
  75. long id) {
  76. mEditText.setText(mPopView.getAdapter().getItem(position).toString());
  77. mPopup.dismiss();
  78. }
  79. }

在构造方法中我们获取了三个自定义的属性:

mDrawableLeft —— 点击下拉的图标

mDropMode —— 下拉菜单显示的模式,是一个枚举类型,提供了wrap_content和flower_parent两种模式,在演示的图片中可以看到两个DropEditText的下拉列表是不同的,第一个是宽度和上面的View相同,使用了flower_parent类型;第二个是包裹内容,使用了wrap_content类型。

mHit —— 就是EditText的hit。

再看onLayout:

[java] view
plain
copy

  1. @Override
  2. protected void onLayout(boolean changed, int left, int top, int right,
  3. int bottom) {
  4. super.onLayout(changed, left, top, right, bottom);
  5. if(changed && 0 == mDropMode) {
  6. mPopView.setListWidth(getMeasuredWidth());
  7. }
  8. }

一个if语句,表示如果模式为flower_parent时才去设置ListView的宽度,为什么呢? 答案就是:WrapListView默认就是包裹内容的,所以在wrap_content模式下根本不需要任何代码,ListView就是包裹内容的。

接下来就是一个setAdapter的方法了:

[java] view
plain
copy

  1. public void setAdapter(BaseAdapter adapter) {
  2. mPopView.setAdapter(adapter);
  3. mPopup = new再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

原文地址:https://www.cnblogs.com/skiwnchhw/p/10472765.html

时间: 2024-08-04 14:52:27

Android 打造可下拉的EditText--DropEditText的相关文章

Android之——自定义下拉菜单的实现

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/48101651 做过Android开发的童鞋,一般都会遇到这样一种情况,就是Android中原有的下拉控件Spinner过于单调和简单,不能够满足我们实际开发的需求了,这时候就需要我们自己自定义下拉菜单来实现相应的功能,那么,如何实现自定义下拉菜单呢?下面我就来和大家一起实现这个功能. 一.原理 我们这个下拉菜单展示的内容主要以ListView实现,在界面上放置一个文本框,文本框右

Android中自定义下拉样式Spinner

Android中自定义下拉样式Spinner 本文继续介绍android自定义控件系列,自定义Spinner控件的使用. 实现思路 1.定义下拉控件布局(ListView及子控件布局) 2.自定义SpinerPopWindow类 3.定义填充数据的Adapter 效果图 一.定义控件布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http:/

CSS打造三级下拉菜单

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><meta name="keywords" content="站长,网页特效,js特效,广告代码,zzjs,zzjs.net,sky,www.zzjs.net,站长特效 网" /><meta name="d

android控件 下拉刷新pulltorefresh

外国人写的下拉刷新控件,我把他下载下来放在网盘,有时候访问不了github 支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridView.(Horizontal )ScrollView.Fragment上下左右拉动刷新,比下面johannilsson那个只支持ListView的强大的多.并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示,体验更好. 国内网盘地址:http://www.400gb.c

Android UI- PullToRrefresh自定义下拉刷新动画

Android UI- PullToRrefresh自定义下拉刷新动画 如果觉得本文不错,麻烦投一票,2014年博客之星投票地址:http://vote.blog.csdn.net/blogstar2014/details?username=wwj_748#content 本篇博文要给大家分享的是如何使用修改开源项目PullToRrefresh下拉刷新的动画,来满足我们开发当中特定的需求,我们比较常见的一种下拉刷新样式可能是以下这种: 就是下拉列表的时候两个箭头上下翻转,更改日期文本和刷新状态,

Android中实现下拉刷新

需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新: 思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息列表的展示.而下拉刷新要求给消息列表加一个头部,其中有图片(向上/向下箭头)和提示字样(下拉刷新/松开刷新),从 而我们需要做的事情:1.需要做一个head.xm来实现头部的样式定义:2.需要自定义一个继承了ListView的MsgListView,在该类中 将head加在MsgListView对象

android中自定义下拉框(转)

android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在编辑框的下面,然后又很多选项的下拉框,可是我在网上找了一下,没有这种下拉框额,就自己写了一个,看效果图先: ,这个是资料填写的一部分界面,三个下拉框,选择故乡所在地: 点击之后弹出下拉框,选择下面的选项: 三个下拉框时关联的,第一个决定了第二数据内容,第二个决定了第三个数据内容,如果三个全部选好之后

Android自定义ListView下拉刷新

实现的目标是本地有数据并没有刷新.下拉数据及时刷新数据. 我在网上找了某位写的MyListView,这个东西的下拉核心部分还是没有弄明白.非常感谢这位作者. XML布局文件源代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

android 开发-spinner下拉框控件的实现

Android提供实现下拉框功能的非常实用的控件Spinner. spinner控件需要向xml资源文件中添加spinner标签,如下: <Spinner android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/textView