zoukankan      html  css  js  c++  java
  • ListView 泛利

    0ListView基本属性

    1介绍 Listview节约内存的几种写法
    2技巧一:解决ListView的ItemView中带有Button时,OnItemClick无效的问题 
    3技巧二Listview滚动栏的属性
    4技巧三有关美化 android ListView的美化涉及到的一些属性
    5精品代码:android开发之横向滚动/竖向滚动的ListView(固定列头)
    6代码2   android ListView和GridView拖拽移位实现代码

    前言

    基本属性在xml文件里

    ListView属性

    1. 背景色:

    listView设置背景色android:background="@drawable/bg",拖动或者点击list空白位置的时候发现ListItem都变成黑色。

    由于默认的ListItem背景是透明的,而ListView的背景是固定不变的,所以在滚动栏滚动的过程中假设实时地去将当前每一个Item的显示内容跟背景进行混合运算。所以android系统为了优化这个过程用,就使用了一个叫做android:cacheColorHint的属性。在黑色主题下默认的颜色值是#191919,所以就出现了刚才的画面。有一半是黑色的。

    假设你仅仅是换背景的颜色的话,能够直接指定android:cacheColorHint为你所要的颜色;假设你是用图片做背景的话。那也仅仅要将android:cacheColorHint指定为透明(#00000000)就能够了,当然为了美化是要牺牲一些效率的。

    2. android:fadingEdge="none" 去掉上边和下边黑色的阴影

    3. android:divider="@drawable/list_driver" 当中 @drawable/list_driver 是一个图片资源lsitview的每一项之间须要设置一个图片做为间隔

    设置Item之间无间隙

    android:divider="#00000000" 或者在javaCode中例如以下定义:listView.setDividerHeight(0);

    4. android:listSelector="@color/pink" listView item 选中时的颜色。

    默觉得橙黄底色。

    5. android:divider="@drawable/list_driver" 设置切割线的图片资源。假设则仅仅要设置为

    android:divider="@drawable/@null" 不想显示切割线

     

    6. android:scrollbars="none" setVerticalScrollBarEnabled(true); 隐藏listView的滚动栏

    7. android:fadeScrollbars="true" 设置为true就能够实现滚动栏的自己主动隐藏和显示

    8. android:transcriptMode="alwaysScroll" 用ListView或者其他显示大量Items的控件实时跟踪或者查看信息,希望最新的条目能够自己主动滚动到可视范围内。通过设置的控件transcriptMode属性能够将Android平台的控件(支持ScrollBar)自己主动滑动到最底部。

    android:fastScrollEnabled="false"
    android:fastScrollEnabled = "true" 加快滑动速度

    android:drawSelectorOnTop="false" 
    android:scrollingCache="false" ???

    ???

    ??

    ??

    ??

    ??

     

    android:drawSelectorOnTop="true" 点击某一条记录,颜色会显示在最上面,记录上的文字被遮住,所以点击文字不放。文字就看不到

    android:drawSelectorOnTop="false" 点击某条记录不放,颜色会在记录的后面,成为背景色。可是记录内容的文字是可见的

    When set to true, the selector will be drawn over the selected item. Otherwise the selector is drawn behind the selected item. The default value is false.


    9.在ListView中加入属性:
    android:scrollbarTrackVertical="@drawable/scrollbar_vertical_track" android:scrollbarThumbVertical="@drawable/scrollbar_vertical_thumb"
    scrollbar_vertical_track,crollbar_vertical_thumb自己定义的xml文件,放在Drawable中,track是指长条,thumb是指短条,然后再xml中定义短条和长条的样式

     


              <!--
             android:cacheColorHint="#00000000" 缓存的颜色  默认是黄色
             android:divider="#00ffffff" 切割线
             android:dividerHeight="3.0dip" 切割线的宽度
          android:fastScrollEnabled="true" 支持高速滑动
    --> <ListView android:id="@+id/kan_listview" android:layout_width="match_parent" android:layout_height="0dp"
                   android:layout_weight="1"
                 android:cacheColorHint="#00000000"
                 android:divider="#fff"
                 android:fastScrollEnabled="true"
                 android:dividerHeight="1.0dp"
                 android:paddingLeft="3.0dp"
                 android:paddingRight="3.0dp" />


    10.listview不可点击

    mListView.setEnabled(false);


    一.Listview节约内存的几种写法 

    这里有一个优化的地方,就是重用view,这样降低内存消耗,同一时候加快item载入速度。

     

    在getView中优化的地方。大家想必都很情况。以下我总结了三种优化的写法,请大家指正。

     

    第一这是常规写法了 

    重用了convertView,非常大程度上的降低了内存的消耗。通过推断convertView是否为null。是的话就须要产生一个视图出来。然后给这个视图数据,最后将这个视图返回给底层,呈献给用户。 

    特点:假设当前的convertView为null。则通过LayoutInflat产生一个view。 

    复制代码 代码例如以下:


    ViewCode 

    public View getView(intposition,ViewconvertView,ViewGroupparent) 

    if(convertView==null) 

    convertView=LayoutInflater.from(context).inflate(R.layout.section_list_item1,null); 

    TextViewt v_name=(TextView)convertView.findViewById(R.id.contact_contactinfoitem_tv_name); 

    TextViewtv_phone=(TextView)convertView.findViewById(R.id.contact_contactinfoitem_tv_phoneNum); 

    ContactInfo  confo=contacts.get(position); 

    if(confo!=null){//toseteveryitem'stext 

    tv_name.setText(confo.getContactName()); 

    tv_phone.setText(confo.getContact_Phone()); 

    returnconvertView; 



    : 

    反正如今开发都这么写了,那就这么写吧。

    特点,使用了内部类classViewHolder、重用了convertView。 

    差别另外一种写法是。使用了一个暂时变量Viewview=convertView。然后改动view。最后返回view 

    @Override 

    public View getView(int position,View convertView,ViewGroup parent) 

    View view=convertView; 

    ViewHolder holder; 

    if(view==null){ 

    view=LayoutInflater.from(context).inflate(R.layout.section_list_item1,null); 

    holder=new ViewHolder(); 

    holder.tv_name=(TextView)view.findViewById(R.id.contact_contactinfoitem_tv_name); 

    holder.tv_phone=(TextView)view.findViewById(R.id.contact_contactinfoitem_tv_phoneNum); 

    view.setTag(holder); 

    else 

    holder=(ViewHolder)view.getTag(); 

    ContactInfo confo=contacts.get(position); 

    Log.i("my","confo"+confo.getContactName()); 

    if(confo!=null){//toseteveryitem'stext 


    holder.tv_name.setText(confo.getContactName()); 

    holder.tv_phone.setText(confo.getContact_Phone()); 

    returnview; 

    classViewHolder 

    TextViewtv_name,tv_phone; 


    以上就是集中写法,供新手学习和总结。 

     

     

     

    技巧一:解决ListView的ItemView中带有Button时。OnItemClick无效的问题

    button添加

    [html] view plaincopy

    android:focusable="false"  

    android:clickable="false"  


    contentView添加:

    [html] view plaincopy

    android:descendantFocusability="blocksDescendants"  

     

     目的:阻止Button获得触摸事件和点击事件

     

     

     

    技巧二Listview滚动栏的属性

    本文主要介绍android viewandroid:scrollbarStyle属性意义android:scrollbarStyle能够定义滚动栏的样式和位置。可选值有insideOverlayinsideInsetoutsideOverlayoutsideInset四种。



      当中insideoutside分别表示是否在viewpadding区域内,overlayinset表示覆盖在view上或是插在view后面,所以四种值分别表示:



      insideOverlay:默认值。表示在padding区域内而且覆盖在view

      insideInset:表示在padding区域内而且插入在view后面

      outsideOverlay:表示在padding区域外而且覆盖在view上,推荐这个

      outsideInset:表示在padding区域外而且插入在view后面

     


       个人认为outsideOverlay最合适,视觉效果最好。

      我们能够在xml中定义android:scrollbarStyle属性,例如以下:

      android:scrollbarStyle="outsideOverlay"

     

     

     

     

    技巧三有关美化 android ListView的美化涉及到的一些属性

     (2011-12-14 12:08:08)

    标签: 

    杂谈

    分类: android

    用心的朋友应该会发现,listview中在设置了背景之后。会有些问题。


    1.listview在拖动的时候背景图片消失变成黑色背景。等到拖动完成我们自己的背景图片才显示出来。


    listview的上边和下边有黑色的阴影。


    3lsitview的每一项之间须要设置一个图片做为间隔。


    针对以上问题 在listviewxml文件里设置一下语句。


    问题有例如以下代码结解决 android:scrollingCache="false"


    问题用例如以下代码解决:android:fadingEdge="none"  

    问题3  用例如以下代码解决:  android:divider="@drawable/list_driver"  当中  @drawable/list_driver 是一个图片资源

    整体例如以下

     

    1

    <ListView

     

    2

      android:id="@+id/myListView01"

     

    3

      android:layout_width="fill_parent"

     

    4

      android:layout_height="287dip"

     

    5

      android:fadingEdge="none"  

     

    6

      android:divider="@drawable/list_driver"

     

    7

      android:scrollingCache="false"

     

    8

      android:background="@drawable/list">

     

    android:fadeScrollbars="true"

     

    9

      </ListView>


    4. 自己定义listview的时候。当你不使用android:cacheColorHint=“#00000000”会出现以下选中一个空间黑色底色的情况,破坏总体美观度:



    5. 当你不使用android:listSelector属性,默认会显示选中的item为橙黄底色,有时候我们须要去掉这样的效果:

    xml文件里的ListView控件中增加例如以下属性:

    android:listSelector="@drawable/timer_list_selector"

    drawable中定义timer_list_selector的属性值

    timer_list_selector.xml中定义例如以下:

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

    <selector xmlns:android="http://schemas.android.com/apk/res/android">

        <item android:state_selected="true" android:drawable="@android:color/transparent" />

    </selector>

    values目录下的colors.xml中定义transparent例如以下:

    <color name="transparent">#50000000</color>

     

     

     

    精品代码:android开发之横向滚动/竖向滚动的ListView(固定列头)

    因为项目须要。我们须要一个能够横向滚动的,又能够竖向滚动的 表格;经过几天的研究最终搞定,感兴趣的朋友能够了解下哦

     

     

    http://yunpan.cn/cgSrLvraWHfNY  提取码 cfda

     

     

     

     

     

    代码2  android ListViewGridView拖拽移位实现代码

     

     

     

    有些朋友对android中ListView和GridView拖拽移位功能的实现不是非常了解,接下来将具体介绍,须要了解的朋友能够參考下

    关于ListView拖拽移动位置,想必大家并不陌生。比較不错的软件都用到如此功能了.如:搜狐。网易。百度等,可是相比来说还是百度的用户体验较好。不偏心了,以下看几个演示样例:

                


    首先说一下:拖拽ListViewitem就不应该能够随意移动。仅仅应该在ListView所在的范围内,而网易的你看看我都能够移动到状态栏了,尽管你做了处理,可是用户体验我个人感觉不好。在看看百度的,不仅控制了移动范围。更不错的百度的移动起来会时时的换位,看起来相当的形象,所以我觉得这样相当的棒.

    说明一点,我没有那么有才,我也是看别人代码。然后自己整理下.在这里就简单记载一下.

    首先对touch事件的处理,从应用中,我们能够得出,在我们点击后面拖拉图标后。就会创建一个item的影像视图.而且能够移动该影像,而此时的ListView不应该有touch事件.

    onInterceptTouchEvent方法.

    [java]

    复制代码 代码例如以下:


    /*** 

    * touch事件拦截 

    */ 

    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 

    // 按下 

    if (ev.getAction() == MotionEvent.ACTION_DOWN) { 

    int x = (int) ev.getX();// 获取相对与ListViewx坐标 

    int y = (int) ev.getY();// 获取对应与ListViewy坐标 

    dragSrcPosition = dragPosition = pointToPosition(x, y); 

    // 无效不进行处理 

    if (dragPosition == AdapterView.INVALID_POSITION) { 

    return super.onInterceptTouchEvent(ev); 


    // 获取当前位置的视图(可见状态

    ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 

    - getFirstVisiblePosition()); 


    // 获取到的dragPoint事实上就是在你点击指定item项中的高度

    dragPoint = y - itemView.getTop(); 

    // 这个值是固定的:事实上就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏)

    dragOffset = (int) (ev.getRawY() - y); 


    // 获取可拖拽的图标 

    View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 


    // x > dragger.getLeft() - 20这句话为了更好的触摸(-20能够省略) 

    if (dragger != null && x > dragger.getLeft() - 20) { 


    upScrollBounce = getHeight() / 3;// 取得向上滚动的边际。大概为该控件的1/3 

    downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际,大概为该控件的2/3 


    itemView.setDrawingCacheEnabled(true);// 开启cache. 

    Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 依据cache创建一个新的bitmap对象

    startDrag(bm, y);// 初始化影像 

    // return false; 


    return super.onInterceptTouchEvent(ev); 


    这种方法的作用非常easy:当我们摁下的假设是可拖拽的图标,那么进行初始化该Item的映像试图.

    而在这里假设大家对WindowManagerWindowManager.LayoutParams不熟悉的朋友先去參考下这篇文章。要对WindowManager有一定的了解。简单的会应用.

    接下来我们看onTouchEvent事件:

    [java]

    /** 

    触摸事件处理 

    */ 

    @Override 

    public boolean onTouchEvent(MotionEvent ev) { 

    // itemview不为空,且获取的dragPosition有效 

    if (dragImageView != null && dragPosition != INVALID_POSITION) { 

    int action = ev.getAction(); 

    switch (action) { 

    case MotionEvent.ACTION_UP: 

    int upY = (int) ev.getY(); 

    stopDrag(); 

    onDrop(upY); 

    break; 

    case MotionEvent.ACTION_MOVE: 

    int moveY = (int) ev.getY(); 

    onDrag(moveY); 

    break; 

    case MotionEvent.ACTION_DOWN: 

    break; 

    default: 

    break; 

    return true;// 取消ListView滑动


    return super.onTouchEvent(ev); 


    简单说明:首先在Touch中,我们要进行推断,是否点击的是拖动图标,假设是的话,那么对ACTION_MOVE and ACTION_UP对应事件进行处理,而且返回true or false.作用:取消ListView自身的Touch事件.假设不是的话。运行ListView 本身的Touch事件.

    大致就介绍这么多,详细的实现,还是大家看源代码吧,我凝视的还算清晰,仅仅要大家细致看的话,一定能够掌握的,为什么这么说呢,技术仅仅有在掌握了情况下才干够进行拓展.

    对了,提醒大家要理解这三句话:

    getRawX()和getRawY():获得的是相对屏幕的位置.

    getX()和getY():获得的永远是相对view的触摸位置 坐标(这两个值不会超过view的长度和宽度)。

    getLeft , getTop, getBottom,getRight, 这个指的是该控件相对于父控件的距离.

    源代码:

    [java] 

    复制代码 代码例如以下:


    package com.jj.drag; 


    import android.content.Context; 

    import android.graphics.Bitmap; 

    import android.os.AsyncTask; 

    import android.util.AttributeSet; 

    import android.util.Log; 

    import android.view.Gravity; 

    import android.view.MotionEvent; 

    import android.view.View; 

    import android.view.ViewConfiguration; 

    import android.view.ViewGroup; 

    import android.view.WindowManager; 

    import android.widget.AbsListView; 

    import android.widget.AbsListView.OnScrollListener; 

    import android.widget.AdapterView; 

    import android.widget.ImageView; 

    import android.widget.ListView; 


    import com.jj.drag.MainActivity.DragListAdapter; 


    /*** 

    自己定义拖拽ListView 

    * @author zhangjia 

    */ 

    public class DragListView extends ListView { 


    private WindowManager windowManager;// windows窗体控制类 

    private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的參数 


    private int scaledTouchSlop;// 推断滑动的一个距离,scroll的时候会用到(24) 


    private ImageView dragImageView;// 被拖拽的项(item),事实上就是一个ImageView 

    private int dragSrcPosition;// 手指拖动项原始在列表中的位置 

    private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置


    private int dragPoint;// 在当前数据项中的位置 

    private int dragOffset;// 当前视图和屏幕的距离(这里仅仅使用了y方向上


    private int upScrollBounce;// 拖动的时候,開始向上滚动的边界 

    private int downScrollBounce;// 拖动的时候,開始向下滚动的边界 


    private final static int step = 1;// ListView 滑动步伐


    private int current_Step;// 当前步伐


    /*** 

    构造方法 

    * @param context 

    * @param attrs 

    */ 

    public DragListView(Context context, AttributeSet attrs) { 

    super(context, attrs); 


    /*** 

    * touch事件拦截 

    */ 

    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 

    // 按下 

    if (ev.getAction() == MotionEvent.ACTION_DOWN) { 

    int x = (int) ev.getX();// 获取相对与ListViewx坐标 

    int y = (int) ev.getY();// 获取对应与ListViewy坐标 

    dragSrcPosition = dragPosition = pointToPosition(x, y); 

    // 无效不进行处理 

    if (dragPosition == AdapterView.INVALID_POSITION) { 

    return super.onInterceptTouchEvent(ev); 


    // 获取当前位置的视图(可见状态

    ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 

    - getFirstVisiblePosition()); 


    // 获取到的dragPoint事实上就是在你点击指定item项中的高度

    dragPoint = y - itemView.getTop(); 

    // 这个值是固定的:事实上就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏)

    dragOffset = (int) (ev.getRawY() - y); 


    // 获取可拖拽的图标 

    View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 


    // x > dragger.getLeft() - 20这句话为了更好的触摸(-20能够省略) 

    if (dragger != null && x > dragger.getLeft() - 20) { 


    upScrollBounce = getHeight() / 3;// 取得向上滚动的边际。大概为该控件的1/3 

    downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际。大概为该控件的2/3 


    itemView.setDrawingCacheEnabled(true);// 开启cache. 

    Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 依据cache创建一个新的bitmap对象

    startDrag(bm, y);// 初始化影像 


    return super.onInterceptTouchEvent(ev); 


    /** 

    触摸事件处理 

    */ 

    @Override 

    public boolean onTouchEvent(MotionEvent ev) { 

    // itemview不为空。且获取的dragPosition有效 

    if (dragImageView != null && dragPosition != INVALID_POSITION) { 

    int action = ev.getAction(); 

    switch (action) { 

    case MotionEvent.ACTION_UP: 

    int upY = (int) ev.getY(); 

    stopDrag(); 

    onDrop(upY); 

    break; 

    case MotionEvent.ACTION_MOVE: 

    int moveY = (int) ev.getY(); 

    onDrag(moveY); 

    break; 

    case MotionEvent.ACTION_DOWN: 

    break; 

    default: 

    break; 

    return true;// 取消ListView滑动


    return super.onTouchEvent(ev); 


    /** 

    准备拖动,初始化拖动项的图像 

    * @param bm 

    * @param y 

    */ 

    private void startDrag(Bitmap bm, int y) { 

    // stopDrag(); 

    /*** 

    初始化window. 

    */ 

    windowParams = new WindowManager.LayoutParams(); 

    windowParams.gravity = Gravity.TOP; 

    windowParams.x = 0; 

    windowParams.y = y - dragPoint + dragOffset; 

    windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; 

    windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; 


    windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需获取焦点 

    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受触摸事件 

    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持设备常开,并保持亮度不变。

     

    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗体占满整个屏幕,忽略周围的装饰边框(比如状态栏)。此窗体需考虑到装饰边框的内容。 


    // windowParams.format = PixelFormat.TRANSLUCENT;// 默觉得不透明,这里设成透明效果

    windowParams.windowAnimations = 0;// 窗体所使用的动画设置 


    ImageView imageView = new ImageView(getContext()); 

    imageView.setImageBitmap(bm); 

    windowManager = (WindowManager) getContext().getSystemService("window"); 

    windowManager.addView(imageView, windowParams); 

    dragImageView = imageView; 



    /** 

    拖动运行。在Move方法中运行 

    * @param y 

    */ 

    public void onDrag(int y) { 

    int drag_top = y - dragPoint;// 拖拽viewtop值不能<0,否则则出界

    if (dragImageView != null && drag_top >= 0) { 

    windowParams.alpha = 0.5f;// 透明度 

    windowParams.y = y - dragPoint + dragOffset;// 移动y.//记得要加上dragOffsetwindowManager计算的是整个屏幕.(标题栏和状态栏都要算上

    windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动

    // 为了避免滑动到切割线的时候。返回-1的问题 

    int tempPosition = pointToPosition(0, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 


    doScroller(y); 


    /*** 

    * ListView的移动

    要明确移动原理:当映像移动到下端的时候。ListView向上滑动,当映像移动到上端的时候,ListView要向下滑动。

    正好和实际的相反

    */ 


    public void doScroller(int y) { 

    Log.e("jj", "y=" + y); 

    Log.e("jj", "upScrollBounce=" + upScrollBounce); 

    // ListView须要下滑 

    if (y < upScrollBounce) { 

    current_Step = step + (upScrollBounce - y) / 10;// 时时步伐 

    }// ListView须要上滑 

    else if (y > downScrollBounce) { 

    current_Step = -(step + (y - downScrollBounce)) / 10;// 时时步伐 

    } else { 

    current_Step = 0; 


    // 获取你拖拽滑动到位置及显示item对应的view上(注:可显示部分)(position) 

    View view = getChildAt(dragPosition - getFirstVisiblePosition()); 

    // 真正滚动的方法setSelectionFromTop() 

    setSelectionFromTop(dragPosition, view.getTop() + current_Step); 



    /** 

    停止拖动,删除影像 

    */ 

    public void stopDrag() { 

    if (dragImageView != null) { 

    windowManager.removeView(dragImageView); 

    dragImageView = null; 


    /** 

    拖动放下的时候 

    * @param y 

    */ 

    public void onDrop(int y) { 


    // 为了避免滑动到切割线的时候,返回-1的问题 

    int tempPosition = pointToPosition(0, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 


    // 超出边界处理(假设向上超过第二项Top的话。那么就放置在第一个位置

    if (y < getChildAt(0).getTop()) { 

    // 超出上边界 

    dragPosition = 0; 

    // 假设拖动超过最后一项的最下边那么就防止在最下边 

    } else if (y > getChildAt(getChildCount() - 1).getBottom()) { 

    // 超出下边界 

    dragPosition = getAdapter().getCount() - 1; 


    // 数据交换 

    if (dragPosition < getAdapter().getCount()) { 

    DragListAdapter adapter = (DragListAdapter) getAdapter(); 

    adapter.update(dragSrcPosition, dragPosition); 



    }


    以下我说下适配器:

    [java] 

    复制代码 代码例如以下:


    /*** 

    自己定义适配器 

    * @author zhangjia 

    */ 

    class DragListAdapter extends BaseAdapter { 

    private ArrayList<String> arrayTitles; 

    private ArrayList<Integer> arrayDrawables; 

    private Context context; 


    public DragListAdapter(Context context, ArrayList<String> arrayTitles, 

    ArrayList<Integer> arrayDrawables) { 

    this.context = context; 

    this.arrayTitles = arrayTitles; 

    this.arrayDrawables = arrayDrawables; 


    @Override 

    public View getView(int position, View convertView, ViewGroup parent) { 

    View view = convertView; 

    /*** 

    在这里尽可能每次都进行实例化新的。这样在拖拽ListView的时候不会出现错乱

    详细原因不明,只是这样经过測试,眼下没有发现错乱。虽说效率不高,可是做拖拽LisView足够了。 

    */ 

    view = LayoutInflater.from(context).inflate( 

    R.layout.drag_list_item, null); 


    TextView textView = (TextView) view 

    .findViewById(R.id.tv_drag_list_item_text); 

    ImageView imageView = (ImageView) view 

    .findViewById(R.id.iv_drag_list_item_1); 

    imageView.setImageResource(arrayDrawables.get(position)); 

    textView.setText(arrayTitles.get(position)); 

    return view; 


    /*** 

    动态改动ListVIiw的方位

    * @param start 

    点击移动的position 

    * @param down 

    松开时候的position 

    */ 

    public void update(int start, int down) { 

    // 获取删除的东东

    String title = arrayTitles.get(start); 

    int drawable_id = arrayDrawables.get(start); 


    arrayTitles.remove(start);// 删除该项 

    arrayDrawables.remove(start);// 删除该项 


    arrayTitles.add(down, title);// 加入删除项 

    arrayDrawables.add(down, drawable_id);// 加入删除项 


    notifyDataSetChanged();// 刷新ListView 


    @Override 

    public int getCount() { 


    return Title.length; 


    @Override 

    public Object getItem(int position) { 

    return Title[position]; 


    @Override 

    public long getItemId(int position) { 

    return position; 



    这里只是多解释了,相信大家都看的明确.假设疑问请留言.

    展示下执行效果:

    效果看起来还行吧,假设认为不错的话,记得要赞一个哦.

    以下我们接着改动,模拟百度嘛。谁让百度这么牛叉呢.

    思路:点中拖拉图标的时候,每次移动仅仅要dragPosition发生改变。也就是我移动到了下一个位置,那么此时我就进行交换运行update.而且除了第一次移动外,在每次交换后要除去映射源的显示。这样用户认为这里的空位就是就是为我准备的,比較人性化.

    实现起来并不复杂,前提是你得掌握上面的操作.

    源代码例如以下;

    [java]

    复制代码 代码例如以下:


    package com.jj.drag; 


    import android.content.Context; 

    import android.graphics.Bitmap; 

    import android.graphics.Color; 

    import android.os.AsyncTask; 

    import android.util.AttributeSet; 

    import android.util.Log; 

    import android.view.Gravity; 

    import android.view.MotionEvent; 

    import android.view.View; 

    import android.view.ViewConfiguration; 

    import android.view.ViewGroup; 

    import android.view.WindowManager; 

    import android.widget.AbsListView; 

    import android.widget.AbsListView.OnScrollListener; 

    import android.widget.AdapterView; 

    import android.widget.ImageView; 

    import android.widget.ListView; 


    import com.jj.drag.MainActivity.DragListAdapter; 


    public class DragListView extends ListView { 


    private WindowManager windowManager;// windows窗体控制类 

    private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的參数 


    private int scaledTouchSlop;// 推断滑动的一个距离,scroll的时候会用到(24) 


    private ImageView dragImageView;// 被拖拽的项(item),事实上就是一个ImageView 

    private int dragSrcPosition;// 手指拖动项原始在列表中的位置 

    private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置


    private int dragPoint;// 在当前数据项中的位置 

    private int dragOffset;// 当前视图和屏幕的距离(这里仅仅使用了y方向上


    private int upScrollBounce;// 拖动的时候,開始向上滚动的边界 

    private int downScrollBounce;// 拖动的时候,開始向下滚动的边界 


    private final static int step = 1;// ListView 滑动步伐


    private int current_Step;// 当前步伐


    private int temChangId;// 暂时交换id 


    private boolean isLock;// 是否上锁


    public void setLock(boolean isLock) { 

    this.isLock = isLock; 


    public DragListView(Context context, AttributeSet attrs) { 

    super(context, attrs); 

    scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 


    /*** 

    * touch事件拦截 在这里我进行对应拦截, 

    */ 

    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 

    // 按下 

    if (ev.getAction() == MotionEvent.ACTION_DOWN && !isLock) { 

    int x = (int) ev.getX();// 获取相对与ListViewx坐标 

    int y = (int) ev.getY();// 获取对应与ListViewy坐标 

    temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y); 

    // 无效不进行处理 

    if (dragPosition == AdapterView.INVALID_POSITION) { 

    return super.onInterceptTouchEvent(ev); 


    // 获取当前位置的视图(可见状态

    ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 

    - getFirstVisiblePosition()); 


    // 获取到的dragPoint事实上就是在你点击指定item项中的高度

    dragPoint = y - itemView.getTop(); 

    // 这个值是固定的:事实上就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏)

    dragOffset = (int) (ev.getRawY() - y); 


    // 获取可拖拽的图标 

    View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 


    // x > dragger.getLeft() - 20这句话为了更好的触摸(-20能够省略) 

    if (dragger != null && x > dragger.getLeft() - 20) { 


    upScrollBounce = getHeight() / 3;// 取得向上滚动的边际,大概为该控件的1/3 

    downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际,大概为该控件的2/3 

    itemView.setBackgroundColor(Color.BLUE); 

    itemView.setDrawingCacheEnabled(true);// 开启cache. 

    Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 依据cache创建一个新的bitmap对象

    startDrag(bm, y);// 初始化影像 

    return false; 


    return super.onInterceptTouchEvent(ev); 


    /** 

    触摸事件处理 

    */ 

    @Override 

    public boolean onTouchEvent(MotionEvent ev) { 

    // itemview不为空,且获取的dragPosition有效 

    if (dragImageView != null && dragPosition != INVALID_POSITION 

    && !isLock) { 

    int action = ev.getAction(); 

    switch (action) { 

    case MotionEvent.ACTION_UP: 

    int upY = (int) ev.getY(); 

    stopDrag(); 

    onDrop(upY); 

    break; 

    case MotionEvent.ACTION_MOVE: 

    int moveY = (int) ev.getY(); 

    onDrag(moveY); 


    break; 

    case MotionEvent.ACTION_DOWN: 

    break; 

    default: 

    break; 

    return true;// 取消ListView滑动


    return super.onTouchEvent(ev); 


    /** 

    准备拖动。初始化拖动项的图像 

    * @param bm 

    * @param y 

    */ 

    private void startDrag(Bitmap bm, int y) { 

    // stopDrag(); 

    /*** 

    初始化window. 

    */ 

    windowParams = new WindowManager.LayoutParams(); 

    windowParams.gravity = Gravity.TOP; 

    windowParams.x = 0; 

    windowParams.y = y - dragPoint + dragOffset; 

    windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; 

    windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; 


    windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需获取焦点 

    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受触摸事件 

    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持设备常开。并保持亮度不变。

     

    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗体占满整个屏幕,忽略周围的装饰边框(比如状态栏)。

    此窗体需考虑到装饰边框的内容。 


    // windowParams.format = PixelFormat.TRANSLUCENT;// 默觉得不透明。这里设成透明效果

    windowParams.windowAnimations = 0;// 窗体所使用的动画设置 


    ImageView imageView = new ImageView(getContext()); 

    imageView.setImageBitmap(bm); 

    windowManager = (WindowManager) getContext().getSystemService("window"); 

    windowManager.addView(imageView, windowParams); 

    dragImageView = imageView; 



    /** 

    拖动运行,在Move方法中运行 

    * @param y 

    */ 

    public void onDrag(int y) { 

    int drag_top = y - dragPoint;// 拖拽viewtop值不能<0。否则则出界

    if (dragImageView != null && drag_top >= 0) { 

    windowParams.alpha = 0.5f; 

    windowParams.y = y - dragPoint + dragOffset; 

    windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动

    // 为了避免滑动到切割线的时候,返回-1的问题 

    int tempPosition = pointToPosition(0, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 


    onChange(y);// 时时交换 


    doScroller(y);// listview移动


    /*** 

    * ListView的移动

    要明确移动原理:当我移动到下端的时候,ListView向上滑动,当我移动到上端的时候,ListView要向下滑动。正好和实际的相反

    */ 


    public void doScroller(int y) { 

    // Log.e("jj", "y=" + y); 

    // Log.e("jj", "upScrollBounce=" + upScrollBounce); 

    // ListView须要下滑 

    if (y < upScrollBounce) { 

    current_Step = step + (upScrollBounce - y) / 10;// 时时步伐 

    }// ListView须要上滑 

    else if (y > downScrollBounce) { 

    current_Step = -(step + (y - downScrollBounce)) / 10;// 时时步伐 

    } else { 

    current_Step = 0; 


    // 获取你拖拽滑动到位置及显示item对应的view上(注:可显示部分)(position) 

    View view = getChildAt(dragPosition - getFirstVisiblePosition()); 

    // 真正滚动的方法setSelectionFromTop() 

    setSelectionFromTop(dragPosition, view.getTop() + current_Step); 



    /** 

    停止拖动,删除影像 

    */ 

    public void stopDrag() { 

    if (dragImageView != null) { 

    windowManager.removeView(dragImageView); 

    dragImageView = null; 


    /*** 

    拖动时时change 

    */ 

    private void onChange(int y) { 

    // 数据交换 

    if (dragPosition < getAdapter().getCount()) { 

    DragListAdapter adapter = (DragListAdapter) getAdapter(); 

    adapter.isHidden = false; 

    if (dragPosition != temChangId) { 

    adapter.update(temChangId, dragPosition); 

    temChangId = dragPosition;// 将点击最初所在位置position付给暂时的,用于推断是否换位


    // 为了避免滑动到切割线的时候。返回-1的问题 

    int tempPosition = pointToPosition(0, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 


    // 超出边界处理(假设向上超过第二项Top的话。那么就放置在第一个位置

    if (y < getChildAt(0).getTop()) { 

    // 超出上边界 

    dragPosition = 0; 

    // 假设拖动超过最后一项的最下边那么就防止在最下边 

    } else if (y > getChildAt(getChildCount() - 1).getBottom()) { 

    // 超出下边界 

    dragPosition = getAdapter().getCount() - 1; 



    /** 

    拖动放下的时候 

    * @param y 

    */ 

    public void onDrop(int y) { 

    // 数据交换 

    if (dragPosition < getAdapter().getCount()) { 

    DragListAdapter adapter = (DragListAdapter) getAdapter(); 

    adapter.isHidden = false; 

    adapter.notifyDataSetChanged();// 刷新



    由于我们要时时交换位置。所以将原先的拖动方法onDrop方法移动到onChange.详细的还是看源代码吧.

    另外的就是对适配器的改动。由于你要对特殊的item进行隐藏之类的操作,这些代码我就不写了。我会将案例上传网上。不懂的能够下载源代码.

    好了还是我们来观看下效果吧.

    怎么样,这个效果看起来要比上面那个效果更人性化点吧,我的操作也许有点快,不信的话,你自己手机体验一下吧.

    关于ListView拖拽就讲到这里,如有不足请大家自己创新.

    以下我们接着对GridView的拖拽简单说明.由于这些在项目中我们都会用到,所以既然做到就做全面点吧.好了大家接着往下看吧.

    首先说明。原理一样,都是拖动映像,记录拖动位置,然后调用notifyDataSetChanged更新UI.

    GridView不同的是你要依据xy值共同获取点击的position和移动至的position,而ListView由于不涉及x坐标.

    嗯,最初的原始移动我就不给大家展示了,效果也不是非常友好,我直接展示时时更新的那种方法.效果类是与上面那个时时更新ListView一样。

    原理也一样.以下我们直接看代码吧.

    [java]

    复制代码 代码例如以下:


    package com.jj.draggrid; 


    import java.util.logging.Handler; 


    import com.jj.draggrid.MainActivity.DragGridAdapter; 


    import android.content.Context; 

    import android.graphics.Bitmap; 

    import android.graphics.PixelFormat; 

    import android.util.AttributeSet; 

    import android.util.Log; 

    import android.view.Gravity; 

    import android.view.MotionEvent; 

    import android.view.View; 

    import android.view.ViewGroup; 

    import android.view.WindowManager; 

    import android.widget.AdapterView; 

    import android.widget.BaseAdapter; 

    import android.widget.GridView; 

    import android.widget.ImageView; 

    import android.widget.Toast; 


    /*** 

    自己定义拖拽GridView 

    * @author zhangjia 

    */ 


    public class DragGridView extends GridView { 


    private WindowManager windowManager;// windows窗体控制类 

    private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的參数 


    private int scaledTouchSlop;// 推断滑动的一个距离,scroll的时候会用到(24) 


    private ImageView dragImageView;// 被拖拽的项(item)。事实上就是一个ImageView 

    private int dragSrcPosition;// 手指拖动项原始在列表中的位置 

    private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置


    private int dragPointX;// 在当前数据项中的位置 

    private int dragPointY;// 在当前数据项中的位置 

    private int dragOffsetX;// 当前视图和屏幕的距离(这里仅仅使用了x方向上

    private int dragOffsetY;// 当前视图和屏幕的距离(这里仅仅使用了y方向上


    private int upScrollBounce;// 拖动的时候,開始向上滚动的边界 

    private int downScrollBounce;// 拖动的时候,開始向下滚动的边界 


    private int temChangId;// 暂时交换id 


    private boolean isDoTouch = false;// touch是否可用 


    private boolean isHide = false;// 是否隐藏 


    private Handler handler; 


    public void setDoTouch(boolean isDoTouch) { 

    this.isDoTouch = isDoTouch; 


    public DragGridView(Context context, AttributeSet attrs) { 

    super(context, attrs); 


    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 


    if (ev.getAction() == MotionEvent.ACTION_DOWN) { 

    int x = (int) ev.getX(); 

    int y = (int) ev.getY(); 


    temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y); 


    if (dragPosition == AdapterView.INVALID_POSITION) { 

    return super.onInterceptTouchEvent(ev); 


    ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 

    - getFirstVisiblePosition()); 


    dragPointX = x - itemView.getLeft(); 

    dragPointY = y - itemView.getTop(); 

    dragOffsetX = (int) (ev.getRawX() - x); 

    dragOffsetY = (int) (ev.getRawY() - y); 


    View dragger = itemView.findViewById(R.id.drag_grid_item); 


    /*** 

    推断是否选中拖动图标 

    */ 

    if (dragger != null && dragPointX > dragger.getLeft() 

    && dragPointX < dragger.getRight() 

    && dragPointY > dragger.getTop() 

    && dragPointY < dragger.getBottom() + 20) { 


    upScrollBounce = getHeight() / 4; 

    downScrollBounce = getHeight() * 3 / 4; 


    itemView.setDrawingCacheEnabled(true); 

    Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache()); 

    startDrag(bm, x, y);// 初始话映像 


    dragger.setVisibility(View.INVISIBLE);// 隐藏该项


    return super.onInterceptTouchEvent(ev); 


    @Override 

    public boolean onTouchEvent(MotionEvent ev) { 


    if (dragImageView != null && dragPosition != INVALID_POSITION 

    && isDoTouch) { 

    int action = ev.getAction(); 

    switch (action) { 

    /*** 

    */ 

    case MotionEvent.ACTION_UP: 

    int upX = (int) ev.getX(); 

    int upY = (int) ev.getY(); 

    stopDrag();// 删除映像 

    onDrop(upX, upY);// 松开 

    // isDoTouch = false; 

    break; 

    /*** 

    拖拽item 

    */ 

    case MotionEvent.ACTION_MOVE: 

    int moveX = (int) ev.getX(); 

    int moveY = (int) ev.getY(); 

    onDrag(moveX, moveY);// 拖拽 

    break; 

    case MotionEvent.ACTION_DOWN: 

    int downX = (int) ev.getX(); 

    int downY = (int) ev.getY(); 

    onHide(downX, downY);// 隐藏该项 

    break; 

    default: 

    break; 

    return true; 

    return super.onTouchEvent(ev); 

    /** 

    准备拖动,初始化拖动项的图像 

    * @param bm 

    * @param y 

    */ 

    public void startDrag(Bitmap bm, int x, int y) { 

    windowParams = new WindowManager.LayoutParams(); 

    windowParams.gravity = Gravity.TOP | Gravity.LEFT; 

    windowParams.x = x - dragPointX + dragOffsetX; 

    windowParams.y = y - dragPointY + dragOffsetY; 

    windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; 

    windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; 

    windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 

    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 

    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 

    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 

    windowParams.windowAnimations = 0; 

    ImageView imageView = new ImageView(getContext()); 

    imageView.setImageBitmap(bm); 

    windowManager = (WindowManager) getContext().getSystemService("window"); 

    windowManager.addView(imageView, windowParams); 

    dragImageView = imageView; 

    /*** 

    拖动时时change 

    */ 

    private void onChange(int x, int y) { 

    // 获取适配器 

    DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 

    // 数据交换 

    if (dragPosition < getAdapter().getCount()) { 

    // 不相等的情况下要进行换位,相等的情况下说明正在移动 

    if (dragPosition != temChangId) { 

    adapter.update(temChangId, dragPosition);// 进行换位 

    temChangId = dragPosition;// 将点击最初所在位置position付给暂时的,用于推断是否换位

    // 为了避免滑动到切割线的时候。返回-1的问题 

    int tempPosition = pointToPosition(x, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 

    /*** 

    拖动运行。在Move方法中运行 

    * @param x 

    * @param y 

    */ 

    public void onDrag(int x, int y) { 

    // 移动 

    if (dragImageView != null) { 

    windowParams.alpha = 0.8f; 

    windowParams.x = x - dragPointX + dragOffsetX; 

    windowParams.y = y - dragPointY + dragOffsetY; 

    windowManager.updateViewLayout(dragImageView, windowParams); 

    onChange(x, y);// 时时交换 

    // 滚动 

    if (y < upScrollBounce || y > downScrollBounce) { 

    // 使用setSelection来实现滚动 

    setSelection(dragPosition); 

    /*** 

    隐藏该选项 

    */ 

    private void onHide(int x, int y) { 

    // 获取适配器 

    DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 

    // 为了避免滑动到切割线的时候。返回-1的问题 

    int tempPosition = pointToPosition(x, y); 

    if (tempPosition != INVALID_POSITION) { 

    dragPosition = tempPosition; 

    adapter.setIsHidePosition(dragPosition); 

    /** 

    停止拖动,删除影像 

    */ 

    public void stopDrag() { 

    if (dragImageView != null) { 

    windowManager.removeView(dragImageView); 

    dragImageView = null; 


    /*** 

    拖动放下的时候 

    * @param x 

    * @param y 

    */ 

    public void onDrop(int x, int y) { 


    DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 

    adapter.setIsHidePosition(-1);// 不进行隐藏 

     

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    身份证号验证
    QML学习笔记(七)— 实现可拖拽、编辑、选中的ListView
    通过WebChannel/WebSockets与QML中的HTML交互
    OpenLayers学习笔记(七)— 类似比例尺的距离环(一)
    OpenLayers学习笔记(六)— 拖拽叠加层overlayer
    OpenLayers学习笔记(五)— 拖拽Feature图层
    QML学习笔记(六)- 简单计时器和定时器
    QML学习笔记(五)— 做一个简单的待做事项列表
    OpenLayers学习笔记(四)— QML显示html中openlayers地图的坐标
    OpenLayers学习笔记(三)— QML与HTML通信之 地图上点击添加自由文本
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4852218.html
Copyright © 2011-2022 走看看