欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android自定义View实现可拖拽缩放的矩形框

程序员文章站 2022-06-22 09:05:18
本文实例为大家分享了android自定义view拖拽缩放矩形框的具体代码,供大家参考,具体内容如下在开发项目中,需要一个矩形框来实现截屏功能,并且还需要可以任意拖拽和缩放,这就需要自定义view来实现...

本文实例为大家分享了android自定义view拖拽缩放矩形框的具体代码,供大家参考,具体内容如下

在开发项目中,需要一个矩形框来实现截屏功能,并且还需要可以任意拖拽和缩放,这就需要自定义view来实现了,具体功能如下:

1.自定义view

package com.xinrui.screenshot.view;

import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.rectf;
import android.support.annotation.nullable;
import android.util.attributeset;
import android.util.log;
import android.util.typedvalue;
import android.view.motionevent;
import android.view.view;

public class croprectview extends view {
 
 // 绘制 损害框和损害名称
 private paint mpaint;
 private rectf mrectf;
 
 // 边缘字体
// private borderedtext mborderedtext;
 
 // 标题 或 名字
 private string mtitle;
 // 概率
 private float mconfidence;
 
 // 矩形框 corner 的角度:直角、圆角
 private int mcornerangle;
 
 //直角 默认
 public static final int right_corner = 0;
 //圆角
 public static final int round_corner = 1;
 
 // remove rect
 private int mode;
 private static final int mode_outside = 0x000000aa;/*170*/
 private static final int mode_inside = 0x000000bb;/*187*/
 private static final int mode_point = 0x000000cc;/*204*/
 private static final int mode_illegal = 0x000000dd;/*221*/
 
 private float startx;/*start x location*/
 private float starty;/*start y location*/
 private float endx;/*end x location*/
 private float endy;/*end y location*/
 
 private float currentx;/*x coordinate values while finger press*/
 private float currenty;/*y coordinate values while finger press*/
 
 private float memoryx;/*the last time the coordinate values of x*/
 private float memoryy;/*the last time the coordinate values of y*/
 
 private float mcoverwidth;/*width of selection box*/
 private float mcoverheight;/*height of selection box*/
 
 private static final int accuracy = 100;/*touch accuracy*/
 private int pointposition;/*vertex of a rectangle*/
 
 private static final float minwidth = 100.0f;/*the minimum width of the rectangle*/
 private static final float minheight = 200.0f;/*the minimum height of the rectangle*/
 
 private onlocationlistener mlocationlistener;/*listen to the rect */
 
 private static final float edge_width = 1.8f;
 
 public moveandcroprectview(context context) {
  this(context, null);
 }
 
 public moveandcroprectview(context context, @nullable attributeset attrs) {
  this(context, attrs, 0);
 }
 
 public moveandcroprectview(context context, @nullable attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  initdatas(context);
 }
 
 private void initdatas(context context) {
  mpaint = new paint();
  mrectf = new rectf();
 
  //画笔设置空心
  mpaint.setstyle(paint.style.stroke);
  mpaint.setcolor(color.white);
  mpaint.setstrokewidth(2);
  mpaint.setantialias(true);
 
//  float textsizepx = typedvalue.applydimension(typedvalue.complex_unit_dip,
//    18.0f, context.getresources().getdisplaymetrics());
//  mborderedtext = new borderedtext(textsizepx);
  currentx = 0;
  currenty = 0;
 }
 
 private boolean firstdraw = true;
 
 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
 
//  switch (mcornerangle) {
//   case right_corner:// 绘制 损害框(直角矩形框)
//    drawrect(canvas);
//    break;
//   case round_corner:// 绘制 损害框(圆角矩形框)
//    drawroundrect(canvas);
//    break;
//  }
 
  if (firstdraw) {
   firstdraw = false;
   startx = mrectf.left;
   starty = mrectf.top;
   endx = mrectf.right;
   endy = mrectf.bottom;
 
   mcoverwidth = mrectf.width();
   mcoverheight = mrectf.height();
  }
 
 
  if (mlocationlistener != null) {
   mlocationlistener.locationrect(startx, starty, endx, endy);
  }
 
//  logutils.d("ondraw -- startx: " + startx);
 
  canvas.drawline(startx - edge_width, starty - edge_width,
    endx + edge_width, starty - edge_width, mpaint);/*top 上边框-*/
  canvas.drawline(startx - edge_width, endy + edge_width,
    endx + edge_width, endy + edge_width, mpaint);/*bottom -*/
  canvas.drawline(startx - edge_width, starty - edge_width,
    startx - edge_width, endy + edge_width, mpaint);/*left |*/
  canvas.drawline(endx + edge_width, starty - edge_width,
    endx + edge_width, endy + edge_width, mpaint);/*right |*/
 
  // 绘制名称 和 概率
//  final string labelstring =
//    !textutils.isempty(mtitle)
//      ? string.format("%s %.2f", mtitle, (100 * mconfidence))
//      : string.format("%.2f", (100 * mconfidence));
//
//  // 在 直角矩形框 上写字
//  mborderedtext.drawtext(canvas,
//    startx,
//    starty, labelstring + "%",
//    mpaint);
 }
 
 @suppresswarnings("nullableproblems")
 @override
 public boolean ontouchevent(motionevent event) {
  switch (event.getaction()) {
   case motionevent.action_down:
    memoryx = event.getx();
    memoryy = event.gety();
    checkmode(memoryx, memoryy);
    break;
   case motionevent.action_move: {
    currentx = event.getx();
    currenty = event.gety();
    switch (mode) {
     case mode_illegal:
      recoverfromillegal(currentx, currenty);
      postinvalidate();
      break;
     case mode_outside:
      //do nothing;
      break;
     case mode_inside://拖动
      movebytouch(currentx, currenty);
      postinvalidate();
      break;
     default:
      /*mode_point*/
      movebypoint(currentx, currenty);
      postinvalidate();
      break;
    }
   }
   break;
   case motionevent.action_up:
//    mpaint.setcolor(getcontext().getresources().getcolor(r.color.orange));
    postinvalidate();
    break;
   default:
    break;
  }
  return true;
 }
 
 /*点击顶点附近时的缩放处理*/
 @suppresswarnings("suspiciousnamecombination")
 private void movebypoint(float bx, float by) {
//  logutils.d("movebypoint");
  switch (pointposition) {
   case 0:/*left-up*/
    mcoverwidth = math.abs(endx - bx);
    mcoverheight = math.abs(endy - by);
    //noinspection suspiciousnamecombination
    if (!checklegalrect(mcoverwidth, mcoverheight)) {
     mode = mode_illegal;
    } else {
     refreshlocation(bx, by, endx, endy);
    }
    break;
   case 1:/*right-up*/
    mcoverwidth = math.abs(bx - startx);
    mcoverheight = math.abs(endy - by);
    if (!checklegalrect(mcoverwidth, mcoverheight)) {
     mode = mode_illegal;
    } else {
     refreshlocation(startx, by, bx, endy);
    }
    break;
   case 2:/*left-down*/
    mcoverwidth = math.abs(endx - bx);
    mcoverheight = math.abs(by - starty);
    if (!checklegalrect(mcoverwidth, mcoverheight)) {
     mode = mode_illegal;
    } else {
     refreshlocation(bx, starty, endx, by);
    }
    break;
   case 3:/*right-down*/
    mcoverwidth = math.abs(bx - startx);
    mcoverheight = math.abs(by - starty);
    if (!checklegalrect(mcoverwidth, mcoverheight)) {
     mode = mode_illegal;
    } else {
     refreshlocation(startx, starty, bx, by);
    }
    break;
   default:
    break;
  }
 }
 
 /*刷新矩形的坐标*/
 private void refreshlocation(float isx, float isy, float iex, float iey) {
  this.startx = isx;
  this.starty = isy;
  this.endx = iex;
  this.endy = iey;
 
  mcoverwidth = endx - startx;
  mcoverheight = endy - starty;

 }
 
 /*检测矩形是否达到最小值*/
 private boolean checklegalrect(float cheight, float cwidth) {
  return (cheight > minheight && cwidth > minwidth);
 }
 
 /*从非法状态恢复,这里处理的是达到最小值后能拉伸放大*/
 private void recoverfromillegal(float rx, float ry) {
  if ((rx > startx && ry > starty) && (rx < endx && ry < endy)) {
   mode = mode_illegal;
  } else {
   mode = mode_point;
  }
 }

 /**
  * 判断点在矩形的什么位置
  * @param cx
  * @param cy
  */
 private void checkmode(float cx, float cy) {
  if (cx > startx && cx < endx && cy > starty && cy < endy) {
   mode = mode_inside;//矩形内部
  } else if (nearbypoint(cx, cy) < 4) {
   mode = mode_point;//矩形点上
  } else {
   mode = mode_outside;//矩形外部
  }
 }
 
 /*矩形随手指移动*/
 private void movebytouch(float mx, float my) {/*move center point*/
  float dx = mx - memoryx;
  float dy = my - memoryy;

  startx += dx;
  starty += dy;
  if(startx<=0){
   startx=0;
  }
  if(starty<=0){
   starty=0;
  }
  endx = startx + mcoverwidth;
  endy = starty + mcoverheight;
  if(endx>=1920){
   endx=1920;
   startx=endx-mcoverwidth;
  }
  if(endy>=1080){
   endy=1080;
   starty=endy-mcoverheight;
  }
  memoryx = mx;
  memoryy = my;
 }
 
 /*判断点(inx,iny)是否靠近矩形的4个顶点*/
 private int nearbypoint(float floatx, float floaty) {
  if ((math.abs(startx - floatx) <= accuracy && (math.abs(floaty - starty) <= accuracy))) {/*left-up angle*/
   pointposition = 0;
   return 0;
  }
  if ((math.abs(endx - floatx) <= accuracy && (math.abs(floaty - starty) <= accuracy))) {/*right-up angle*/
   pointposition = 1;
   return 1;
  }
  if ((math.abs(startx - floatx) <= accuracy && (math.abs(floaty - endy) <= accuracy))) {/*left-down angle*/
   pointposition = 2;
   return 2;
  }
  if ((math.abs(endx - floatx) <= accuracy && (math.abs(floaty - endy) <= accuracy))) {/*right-down angle*/
   pointposition = 3;
   return 3;
  }
  pointposition = 100;
  return 100;
 }
 
 // 设置矩形框
 public void setrectf(rectf rectf) {
  this.mrectf = rectf;
 }
 
 public void settitle(string title) {
  mtitle = title;
 }
 
 public void setconfidence(float confidence) {
  mconfidence = confidence;
 }
 
 public void setcornerangle(int cornerangle) {
  this.mcornerangle = cornerangle;
 }
 
 // 绘制 损害框(直角矩形框)
 private void drawrect(canvas canvas) {
 
  canvas.drawrect(mrectf, mpaint);
 
  // 绘制名称 和 概率
//  final string labelstring =
//    !textutils.isempty(mtitle)
//      ? string.format("%s %.2f", mtitle, (100 * mconfidence))
//      : string.format("%.2f", (100 * mconfidence));
 
  // 在 直角矩形框 上写字
//  mborderedtext.drawtext(canvas,
//    mrectf.left,
//    mrectf.top, labelstring + "%",
//    mpaint);
 }
 
 // 绘制 损害框(圆角矩形框)
 private void drawroundrect(canvas canvas) {
  float cornersize = math.min(mrectf.width(), mrectf.height()) / 8.0f;
  canvas.drawroundrect(mrectf, cornersize, cornersize, mpaint);
 
  // 绘制名称 和 概率
//  final string labelstring =
//    !textutils.isempty(mtitle)
//      ? string.format("%s %.2f", mtitle, (100 * mconfidence))
//      : string.format("%.2f", (100 * mconfidence));
 
  // 在 圆角矩形框 上写字
//  mborderedtext.drawtext(canvas,
//    mrectf.left + cornersize,
//    mrectf.top, labelstring + "%",
//    mpaint);
 }
 
 public void setlocationlistener(onlocationlistener mlocationlistener) {
  this.mlocationlistener = mlocationlistener;
 }
 
 public interface onlocationlistener {
  void locationrect(float startx, float starty, float endx, float endy);
 }
 
 
}

2.activity里的应用

package com.xinrui.screenshot;

import android.app.activity;
import android.graphics.rectf;
import android.os.bundle;
import android.util.log;
import android.widget.relativelayout;

import com.xinrui.screenshot.view.croprectview;

public class mainactivity extends activity {
 private relativelayout main_area;
 croprectview croprectview;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  initview();
 }

 private void initview(){
  main_area = (relativelayout)findviewbyid(r.id.main_area);
  croprectview = (croprectview)findviewbyid(r.id.main_img);
  rectf rectf = new rectf(660, 240, 1260, 840);
  croprectview.setrectf(rectf);

  croprectview.setlocationlistener(new croprectview.onlocationlistener() {
   @override
   public void locationrect(float startx, float starty, float endx, float endy) {
    log.e("mainactivity","[ startx:(" + startx + ")--starty:(" + starty + ")--endx:(" + endx + ")--endy:(" + endy + ") ]");
   }
  });
 }
}

3.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<relativelayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/main_area"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <com.xinrui.screenshot.view.croprectview
  android:id="@+id/main_img"
  android:layout_centerinparent="true"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>
</relativelayout>

大功告成。

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