Pro Android学习笔记(一五十):拖拽(4):Android3.0及后的方式(下)

2024-01-28 12:08

本文主要是介绍Pro Android学习笔记(一五十):拖拽(4):Android3.0及后的方式(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。


代码:Paletter-自定义属性

我们在上面的fragment中放入LinearLayout,里面放入我们自定的圆点MyNewDot,相关的layout文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ……  android:orientation="vertical" >
    
    <cn.wei.flowingflying.testdraganddrop.MyNewDot android:id="@+id/dot1"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="30dp" 
        android:tag="Blue Dot" 
        dot:color="#ff3333ff" 
        dot:radius="20dp"
  /> 
  
    <cn.wei.flowingflying.testdraganddrop.MyNewDot android:id="@+id/dot2"
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:padding="10dp" 
        android:tag="Red Dot" 
        dot:color="#ffff3333" 
        dot:radius="30dp"
  /> 
</LinearLayout>

我们注意到在xml文件中有两个自定义的属相dot:color和dot:radius分别定义圆点的颜色和大小。我们在res/values中增加一个attribute.xml文件来对这些自行一属性Dot(不区分大小写)进行描述,定义属性前缀和属性名称,以及属性值的类型,如下。

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <declare-styleable name="Dot"> 
        <attr name="color" format="color"/> 
        <attr name="radius" format="dimension"/> 
   </declare-styleable>
    
</resources> 

Paletter类代码如下,很简单:

public class Palette extends Fragment{ 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
        View v = inflater.inflate(R.layout.palette, container, false); 
        return v; 
    } 
}

我们重点看看如何实现自定义的MyNewDot,我们需要在代码对自定义的属性进行读取,如下:

public class MyNewDot extends View implements OnDragListener{ 
    private String tag = "MyNewDot";      
    private static final int DEFAULT_RADIUS = 20; 
    private static final int DEFAULT_COLOR = Color.BLACK; 
    private static final int SELECTED_COLOR = Color.MAGENTA; 
    private int mRadius = DEFAULT_RADIUS; 
    private int mColor = DEFAULT_COLOR;
  
    private boolean inDrag = false; 

    public MyNewDot(Context context ,AttributeSet attrs){ 
        super(context,attrs); 
        tag = (String)getTag();
 
        
        //【1】读取自定义的属性:根据R.styleable.Dot来解释属性 
       TypedArray myAttrs =  context.obtainStyledAttributes(attrs, R.styleable.Dot);
        int numAttrs = myAttrs.getIndexCount(); 
        for(int i = 0 ; i < numAttrs; i ++){ 
            int attr = myAttrs.getIndex(i);  
            switch(attr){ 
            case R.styleable.Dot_color:  
                mColor = myAttrs.getColor(attr, DEFAULT_COLOR);
 
                break; 
            case R.styleable.Dot_radius:  
                //注意这里的单位是pixel,和xml中的单位不同 
                mRadius = myAttrs.getDimensionPixelSize(attr, DEFAULT_RADIUS);        
                break; 
            } 
        } 
        myAttrs.recycle(); 
        
        Log.v(tag,"radius:" + mRadius + "px  color:" + mColor);            
          
        // 构造一个Paint 
        myNormalPaint = new Paint(); 
        myNormalPaint.setColor(mColor); 
        myNormalPaint.setAntiAlias(true); 
        //构造另一个Paint,当检查到被拖拽时,颜色发生变化 
        myDraggingPaint = new Paint(); 
        myDraggingPaint.setColor(SELECTED_COLOR); 
        myDraggingPaint.setAntiAlias(true);  
    }  

    @Override //【2】根据xml的参数大小,重新设置圆点的size,如果不重新进行设定,则尽可能占空间,小例子有上下两个圆点,第一个控件将占满parent的空间,第二个控件的高度为0,要计算真实需要的空间
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
        int size = 2 * mRadius + getPaddingLeft() + getPaddingRight();  
        setMeasuredDimension(size, size); 
    }   

    @Override //【3】画圆点
    public void draw(Canvas canvas) {
  
        //计算圆心  
        float cx = this.getWidth()/2 + getLeftPaddingOffset(); 
        float cy = this.getHeight()/2 + getTopPaddingOffset();  
        //设置paint 
        Paint paint = inDrag ? myDraggingPaint : myNormalPaint;      
        canvas.drawCircle(cx, cy, mRadius, paint); 
        invalidate(); //重画 
    }    

}

代码:启动拖拽

当检测到用户长按圆点时,表示要启动拖拽,相关代码如下:

public MyNewDot(Context context ,AttributeSet attrs){ 
    ...... 
    //当检测到常按是,启动拖拽 
    setOnLongClickListener(new OnLongClickListener() { 
        private boolean mDragInProgress; 
        @Override 
        public boolean onLongClick(View v) { 
            // 在ClipData中携带信息,小例子只简单地携带tag信息,可以用来标识view  
            ClipData data = ClipData.newPlainText("DragData", (String)v.getTag()); 
            //startDrag()启动拖拽,方法中第一个参数是ClipData;第二个参数是通过DragShadowBuilder()创建拖拽的暗影,当然也可以设置为其他的形状的view;第三个参数是local-state对象,可放入DragEvent用来传递信息,通过event.getLocalState()获取,本例,我们就将被拖拽view作为对象进行传递;第四个参数flag,设置为0。
            mDragInProgress = v.startDrag(data, new View.DragShadowBuilder(v), (Object) v, 0);
            Log.v((String)v.getTag(), "Starting drag ? " + mDragInProgress);             
            return true; 
        } 
    }); 

实际上被拖拽的圆点本身一般并不需要进行监听拖拽,我们只是进一步地学习onDrag()的监听触发机制。为此,我们在检测到started的时候,改变圆点的颜色,并在结束时ended,恢复圆点的颜色。相关代码如下:

public class MyNewDot extends View implements OnDragListener
    public MyNewDot(Context context ,AttributeSet attrs){ 
        ......        
        setOnDragListener(this); //设置监听器
    } 

    ... ... 

   @Override /* 我们在检测到started的时候,改变圆点颜色,并在结束时ended,恢复圆点的颜色*/
    public boolean onDrag(View v, DragEvent event) {  
        String dotTag = (String)v.getTag(); 
        
        // 判断是否拖拽本view,在小例子中,有两个MyNewDot进行拖拽,需要进行判断是否是我们所关心的对象,本例子,已经在localState中设置为被拖拽对象,可用来进行比较,如果不是自己,直接返回false。 注意onDrag()中第一个参数是接收拖拽事件的对象,而非被拖拽的对象,本例就是this自己
        if(event.getLocalState() !=this){ 
           Log.v(dotTag,"This Drag event is not for use");
            return false; 
        } 
        
        boolean result = true;        
        float x = event.getX(); 
        float y = event.getY();  
        //当检测到start时,改变颜色,当检测到end时,恢复颜色,其他的action给出log,帮助学习onDrag()
        switch(event.getAction()){ 
        case DragEvent.ACTION_DRAG_STARTED: 
            Log.v(dotTag,"Drag started. x=" + x + " y=" + y);
            inDrag = true; 
            break; 
        
        case DragEvent.ACTION_DRAG_LOCATION: //在圆点区域内,位置移动会触发
            Log.v(dotTag,"Drag processing... x=" + x + " y=" + y);
            break; 
            
        case DragEvent.ACTION_DRAG_ENTERED:  //在started后,我们马上看到entered,因为圆点一开始就在自己的位置上,所以一开始就entered
            Log.v(dotTag,"Drag entered at x=" + x + " y=" + y);
            break; 
        
        case DragEvent.ACTION_DRAG_EXITED: //圆点拖拽的暗影离开圆点区域
            Log.v(dotTag,"Drag exited at x=" + x + " y=" + y);
            break; 
        
        case DragEvent.ACTION_DROP:  //对于圆点在自己的区域内drop,圆点不关心,因为它是被拖拽的对象,不是目标位置对象,无需任何处理,可以返回false,不过下个动作就是ended,返回true也无所谓。
            Log.v(dotTag,"Drag droped at x=" + x + " y=" + y); 
            break; 
            
        case DragEvent.ACTION_DRAG_ENDED: 
            Log.v(dotTag,"Drag ended. x=" + x + " y=" + y);
            inDrag = false; 
            break; 
        
        default: 
            Log.v(dotTag,"Drag other action :  " + action + " x=" + x + " y=" + y);
            result = false; 
            break; 
        }     
         
        return result; 
    } 
    
}

相关小例子代码:Pro Android学习:拖拽小例子

这篇关于Pro Android学习笔记(一五十):拖拽(4):Android3.0及后的方式(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/653588

相关文章

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

Mycat搭建分库分表方式

《Mycat搭建分库分表方式》文章介绍了如何使用分库分表架构来解决单表数据量过大带来的性能和存储容量限制的问题,通过在一对主从复制节点上配置数据源,并使用分片算法将数据分配到不同的数据库表中,可以有效... 目录分库分表解决的问题分库分表架构添加数据验证结果 总结分库分表解决的问题单表数据量过大带来的性能

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

SpringBoot项目引入token设置方式

《SpringBoot项目引入token设置方式》本文详细介绍了JWT(JSONWebToken)的基本概念、结构、应用场景以及工作原理,通过动手实践,展示了如何在SpringBoot项目中实现JWT... 目录一. 先了解熟悉JWT(jsON Web Token)1. JSON Web Token是什么鬼

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C