热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android如何创建可拖动的图片控件

这篇文章主要为大家详细介绍了Android如何创建可拖动的图片控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android创建可拖动图片控件的具体代码,供大家参考,具体内容如下

重载、自绘

1、从View派生一个控件类 ,构造函数中调用父类构造器。

2、重载其onDraw函数,在里面绘制图片。(和windows的MFC有种似曾相识的感觉,可能安卓借鉴了windows的模式吧)

消息处理

拖动图片的消息,主要是处理按下和移动两个消息,重载onTouchEvent。数学知识(平移):在ACTION_DOWN时记录下坐标点,在ACTION_MOVE时根据当前位置与按下时的位置算出平移量。刷新控件,导致控件重绘,重绘时移动绘制的左上角坐标即可。

刚开始时,只是收到了ACTION_DOWN消息,ACTION_MOVE消息就是捕捉不到,上网搜了下,原来是我在onTouchEvent最后调用了父类函数return super.onTouchEvent(event);父类里面返回false表示对这些消息不予关注,后续的ACTION_MOVE和ACTION_UP就不会进来了。

代码和配置

activity的XML配置

 
   

 控件的自绘代码

package com.example.timertest; 
 
 
import java.util.ArrayList; 
import android.annotation.SuppressLint; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.PointF; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.WindowManager; 
 
@SuppressLint("ClickableViewAccessibility") 
public class DragImageView extends View{ 
   
  private Bitmap bmp = null; 
  private PointF orgPos = new PointF(0, 0); 
  private PointF downPos = new PointF(0, 0); 
  private PointF movePos = new PointF(0, 0); 
  private boolean bMove = false; 
  private int nDstWidth = 0; 
  private int nDstHeight = 0; 
  private Rect rcSrc = new Rect(0, 0 , 0, 0); 
  private RectF rcDst = new RectF(0, 0, 0, 0); 
  private Paint paint = null; 
  public DragImageView(Context context) { 
    super(context); 
    // TODO Auto-generated constructor stub 
    paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
    //setOnClickListener(new DivOnClickListener()); 
    //setOnTouchListener(l); 
  } 
   
  public DragImageView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    //bmp = img; 
    paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
  } 
  public DragImageView(Context context, AttributeSet attrs, int defStyleAttr){ 
    super(context, attrs, defStyleAttr); 
    paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
  } 
   
  public void SetImage(Bitmap img){ 
    if ( bmp != null ){ 
      bmp = null; 
    } 
    bmp = img; 
  } 
 
  @Override 
  public void addTouchables(ArrayList views) { 
    // TODO Auto-generated method stub 
    super.addTouchables(views); 
  } 
 
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
    // TODO Auto-generated method stub 
    float fPosX = event.getX(); 
    float fPosY = event.getY(); 
    int nAct = event.getAction(); 
    switch ( nAct ){ 
    case MotionEvent.ACTION_MOVE:{ 
      if ( !bMove ) 
        bMove = true; 
      movePos.x = fPosX - downPos.x; 
      movePos.y = fPosY - downPos.y; 
      downPos.x = fPosX; 
      downPos.y = fPosY; 
      invalidate(); 
    } 
      break; 
    case MotionEvent.ACTION_DOWN:{ 
      downPos.x = fPosX; 
      downPos.y = fPosY; 
    } 
      break; 
    case MotionEvent.ACTION_UP: 
      break; 
    } 
    //一定要返回ture,如果返回父类方法即false,则后续的move up 消息都不会触发。 
    return true; 
    //return super.onTouchEvent(event); 
  } 
 
  @Override 
  protected void onDraw(Canvas canvas) { 
    // TODO Auto-generated method stub 
    super.onDraw(canvas); 
    if ( bmp == null ) 
      return ; 
    int nWidth = bmp.getWidth(); 
    int nHeight = bmp.getHeight(); 
    if ( !bMove ){ 
      orgPos = GetCenterPos(); 
    } 
    else{ 
      orgPos.x += movePos.x; 
      orgPos.y += movePos.y; 
    } 
    rcSrc.right = nWidth; 
    rcSrc.bottom = nHeight; 
    rcDst.left = orgPos.x; 
    rcDst.top = orgPos.y; 
    rcDst.right = orgPos.x+nDstWidth; 
    rcDst.bottom = orgPos.y+nDstHeight; 
    canvas.drawBitmap(bmp, rcSrc, rcDst, paint); 
  } 
   
  protected PointF GetCenterPos(){ 
    PointF pt = new PointF(0, 0); 
    if ( bmp == null ) 
      return pt; 
    WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE); 
    //wm.getDefaultDisplay().getSize(pt); 
    int nScrWidth = wm.getDefaultDisplay().getWidth(); 
    @SuppressWarnings("deprecation") 
    int nScrHeight = wm.getDefaultDisplay().getHeight(); 
    int nWidth = bmp.getWidth(); 
    int nHeight = bmp.getHeight(); 
    float fImgRate = nWidth/(float)nHeight; 
    float fScrRate = nScrWidth/(float)nScrHeight; 
    if ( nWidth>nScrWidth && nHeight>nScrHeight ){ 
      if ( fImgRate > fScrRate ){ 
         
        nDstWidth = nScrWidth; 
        nDstHeight = (int)(nScrWidth/fImgRate); 
 
      } 
      else{ 
         
        nDstHeight = nScrHeight; 
        nDstWidth= (int)(nScrHeight*fImgRate); 
   
      } 
    } 
    else if ( nWidth>nScrWidth ){ 
      nDstWidth = nScrWidth; 
      nDstHeight = nHeight; 
    } 
    else if ( nHeight>nScrHeight ){ 
      nDstWidth = nWidth; 
      nDstHeight = nScrHeight; 
    } 
    else{ 
      nDstWidth = nWidth; 
      nDstHeight = nHeight; 
    } 
    pt.y = (nScrHeight-nDstHeight)/2.0f; 
    pt.x = (nScrWidth-nDstWidth)/2.0f; 
    return pt; 
  } 
   
 
} 

其中GetCenterPos函数是根据图片尺寸计算适合屏幕居中的方法。

运行程序

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 蒜头君的倒水问题(矩阵快速幂优化)
    蒜头君将两杯热水分别倒入两个杯子中,每杯水的初始量分别为a毫升和b毫升。为了使水冷却,蒜头君采用了一种特殊的方式,即每次将第一杯中的x%的水倒入第二杯,同时将第二杯中的y%的水倒入第一杯。这种操作会重复进行k次,最终求出两杯水中各自的水量。 ... [详细]
  • 经过一年的思考,我发现自己对开发的兴趣并不浓厚,而对算法研究则更加热衷。本文将探讨开发与算法之间的本质差异,并分享我的未来学习计划。 ... [详细]
  • PHP 5.5.31 和 PHP 5.6.17 安全更新发布
    PHP 5.5.31 和 PHP 5.6.17 已正式发布,主要包含多个安全修复。强烈建议所有用户尽快升级至最新版本以确保系统安全。 ... [详细]
  • 使用 Git Rebase -i 合并多个提交
    在开发过程中,频繁的小改动往往会生成多个提交记录。为了保持代码仓库的整洁,我们可以使用 git rebase -i 命令将多个提交合并成一个。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • NX二次开发:UFUN点收集器UF_UI_select_point_collection详解
    本文介绍了如何在NX中使用UFUN库进行点收集器的二次开发,包括必要的头文件包含、初始化和选择点集合的具体实现。 ... [详细]
  • 解决SQL Server数据库sa登录名无法连接的问题
    在安装SQL Server数据库后,使用Windows身份验证成功,但使用SQL Server身份验证时遇到问题。本文将介绍如何通过设置sa登录名的密码、启用登录名状态以及开启TCP协议来解决这一问题。 ... [详细]
  • MySQL 数据库连接方法
    本文介绍了如何使用 MySQL 命令行工具连接到指定的数据库。 ... [详细]
  • 本文详细介绍了如何在PHP中记录和管理行为日志,包括ThinkPHP框架中的日志记录方法、日志的用途、实现原理以及相关配置。 ... [详细]
  • 如何解决8080端口被占用问题
    本文介绍了如何通过命令行和任务管理器查找并终止占用8080端口的进程,以确保该端口能够正常使用。 ... [详细]
  • Excel 数据分析基础
    Excel 是数据分析中最基本且强大的工具之一,具备多种实用功能和操作方法。本文将简要介绍 Excel 的不同版本及其兼容性问题,并探讨在处理大数据时的替代方案。 ... [详细]
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
  • LDAP服务器配置与管理
    本文介绍如何通过安装和配置SSSD服务来统一管理用户账户信息,并实现其他系统的登录调用。通过图形化交互界面配置LDAP服务器,确保用户账户信息的集中管理和安全访问。 ... [详细]
  • Android 自定义 RecycleView 左滑上下分层示例代码
    为了满足项目需求,需要在多个场景中实现左滑删除功能,并且后续可能在列表项中增加其他功能。虽然网络上有很多左滑删除的示例,但大多数封装不够完善。因此,我们尝试自己封装一个更加灵活和通用的解决方案。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
author-avatar
Amyb__ing舒
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有