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

Android简单实现画图功能

这篇文章主要为大家详细介绍了Android简单实现画图功能的方法,以及实现过程中遇到的问题,感兴趣的小伙伴们可以参考一下

如何在图片上画画呢?这里写了一个demo,供大家参考
一、先看一眼工程结构
工程结构:

二、自定义view
这个自定义view实现了保留轨迹的功能,代码如下

package picturegame.view; 
 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Paint.Style; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 
import com.winton.picturegame.R; 
 
public class GameView extends View{ 
   
  private Paint paint = null; // 
   
  private Bitmap originalBitmap = null;//原始图 
   
  private Bitmap new1Bitmap = null; 
   
  private Bitmap new2Bitmap = null; 
   
  private float clickX =0; 
   
  private float clickY=0; 
   
  private float startX=0; 
   
  private float startY=0; 
   
  private boolean isMove = true; 
   
  private boolean isClear = false; 
   
  private int color =Color.RED;//默认画笔颜色为红色 
   
  private float strokeWidth =2.0f;//默认画笔粗度 
   
   
 
  public GameView(Context context) { 
    this(context,null); 
    // TODO Auto-generated constructor stub 
  } 
  public GameView(Context context,AttributeSet atts) { 
    this(context,atts,0); 
    // TODO Auto-generated constructor stub 
  } 
  public GameView(Context context,AttributeSet atts,int defStyle) { 
    super(context,atts,defStyle); 
    // TODO Auto-generated constructor stub 
     
    originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_pic).copy(Bitmap.Config.ARGB_8888, true);//加载一张背景 
    new1Bitmap=originalBitmap.createBitmap(originalBitmap); 
  } 
 
  //清除函数 
  public void clear(){ 
    isClear =true; 
    new2Bitmap=originalBitmap.createBitmap(originalBitmap); 
    invalidate();//重载 
  } 
   
  public void setStrokeWidth(float width){ 
    this.strokeWidth=width; 
    initPaint(); 
  } 
  @Override 
  protected void onDraw(Canvas canvas) { 
    // TODO Auto-generated method stub 
    super.onDraw(canvas); 
    canvas.drawBitmap(writer(new1Bitmap),0,0, null); 
     
  } 
   
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
    // TODO Auto-generated method stub 
     
     
    clickX =event.getX(); 
     
    clickY=event.getY(); 
     
    if(event.getAction()==MotionEvent.ACTION_DOWN){ 
      isMove =false; 
      invalidate(); 
      return true; 
    } 
    else if(event.getAction()==MotionEvent.ACTION_MOVE){ 
      isMove =true; 
      invalidate(); 
      return true; 
    } 
     
     
    return super.onTouchEvent(event); 
  } 
   
  /** 
  * @Title: writer 
  * @Description: TODO(生成bitmap) 
  * @param @param pic 
  * @param @return  设定文件 
  * @return Bitmap  返回类型 
  * @throws 
  */ 
  public Bitmap writer(Bitmap pic){ 
    initPaint(); 
     
    Canvas canvas =null; 
    if(isClear){ 
      canvas=new Canvas(new2Bitmap); 
    }else{ 
      canvas=new Canvas(pic); 
    } 
     
    if(isMove){ 
      canvas.drawLine(startX, startY, clickX, clickY, paint);//划线 
    } 
    startX = clickX; 
     
    startY =clickY; 
    if(isClear){ 
      return new2Bitmap; 
    } 
    return pic; 
  } 
   
  private void initPaint(){ 
     
    paint = new Paint();//新建画笔 
     
    paint.setStyle(Style.STROKE);//设置为画线 
     
    paint.setAntiAlias(true);//可以让线条圆滑一些 
     
    paint.setColor(color);//设置画笔颜色 
     
    paint.setStrokeWidth(strokeWidth);//设置画笔线条的粗细 
  } 
   
  /** 
  * @Title: setColor 
  * @Description: TODO(设置线条颜色的对外接口) 
  * @param @param color  设定文件 
  * @return void  返回类型 
  * @throws 
  */ 
  public void setColor(int color){ 
     
    this.color=color; 
    initPaint(); 
  } 
   
   
} 


三、主页面布局文件
主页面布局文件

 
   
   
     
       
     
     
    
       
     
     
     
       
     
     
     
       
     
     
      
       
     
     
       
     
     
      
       
     
   
   
   
   
       
   
  

四、主Activity代码

package com.winton.picturegame; 
 
import picturegame.view.GameView; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.TextView; 
 
import com.winton.basemodule.BaseActivity; 
 
public class MainActivity extends BaseActivity implements OnClickListener { 
 
  private GameView gameview = null; 
  private Button clear = null; 
   
  private TextView tv30,tv25,tv20,tv15,tv10,tv5,tv2; 
 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    // TODO Auto-generated method stub 
    super.onCreate(savedInstanceState); 
  } 
 
  @Override 
  public void initView() { 
    // TODO Auto-generated method stub 
    setContentView(R.layout.activity_main); 
     
    gameview=(GameView)findViewById(R.id.gameview); 
    clear =(Button)findViewById(R.id.btn_clear); 
    tv30=(TextView)findViewById(R.id.tv_30); 
    tv25=(TextView)findViewById(R.id.tv_25); 
    tv20=(TextView)findViewById(R.id.tv_20); 
    tv15=(TextView)findViewById(R.id.tv_15); 
    tv10=(TextView)findViewById(R.id.tv_10); 
    tv5=(TextView)findViewById(R.id.tv_5); 
    tv2=(TextView)findViewById(R.id.tv_2); 
  } 
 
  @Override 
  public void initListener() { 
    // TODO Auto-generated method stub 
    clear.setOnClickListener(this); 
    tv30.setOnClickListener(this); 
    tv25.setOnClickListener(this); 
    tv20.setOnClickListener(this); 
    tv15.setOnClickListener(this); 
    tv10.setOnClickListener(this); 
    tv5.setOnClickListener(this); 
    tv2.setOnClickListener(this); 
     
  } 
 
  @Override 
  public void initData() { 
    // TODO Auto-generated method stub 
     
  } 
  @Override 
  public void onClick(View v) { 
    // TODO Auto-generated method stub 
    if(v==clear){ 
      gameview.clear(); 
      return; 
    } 
    if(v==tv30){ 
      gameview.setStrokeWidth(30f); 
      return; 
    } 
    if(v==tv25){ 
      gameview.setStrokeWidth(25f); 
      return; 
    } 
    if(v==tv20){ 
      gameview.setStrokeWidth(20f); 
      return; 
    } 
    if(v==tv15){ 
      gameview.setStrokeWidth(15f); 
      return; 
    } 
    if(v==tv10){ 
      gameview.setStrokeWidth(10f); 
      return; 
    } 
    if(v==tv5){ 
      gameview.setStrokeWidth(5f); 
      return; 
    } 
    if(v==tv2){ 
      gameview.setStrokeWidth(2f); 
      return; 
    } 
     
  } 
    
} 

五、效果
运行效果图如下

六、疑问
当线条变粗时,线条会出现如上图中不连续的问题。请问高手这个怎么处理呢?我猜测应该要运行算法,但还不知道怎么运行。

文章就为大家介绍到这,其实还有许多知识点小编也不是很清楚,希望大家可以进行补充扩展,共同进步。


推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
author-avatar
机加工N_918
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有