转载请注明出处:王亟亟的大牛之路

平时要用一些非方方正正的button之类的小伙伴们是怎样实现的?RadioButton?

ImageButton?

还是其它?

今天亟亟上的是ImageView来实现的

先上下效果图(文件夹结构)

分析:

shape.xml用于Button的”倒角”(做过机械类的都懂,哈哈)

attr.xml用于自己定义ImageView的标签的定义

ids.xml用于控件findbyid用,为什么补+id 等会我会来解释

效果图:



分析:一个Button 2个自己定义ImageView然后 这 3个东西都能够拖拽啊,点击啊等操作,我们来分析下代码。

先从圆角Button開始:

 <Button
android:id="@+id/touch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="快来按我"
android:background="@drawable/shape"/>

没什么特别的差别。仅仅是由于@drawable/shape使得他的样式产生了变化

shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 填充的颜色 -->
<solid android:color="#00FF00" />
<!-- 设置button的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="25dip" /> <!-- padding:Button里面的文字与Button边界的间隔 -->
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp"
/>
</shape>

Button就简单的实现了

CycleImageView

public class CycleImageView extends ImageView
{ private Paint mPaint;
private Xfermode mXfermode = new PorterDuffXfermode(Mode.DST_IN);
private Bitmap mMaskBitmap; private WeakReference<Bitmap> mWeakBitmap; /**
* 图片的类型,圆形or圆角
*/
private int type;
public static final int TYPE_CIRCLE = 0;
public static final int TYPE_ROUND = 1;
/**
* 圆角大小的默认值
*/
private static final int BODER_RADIUS_DEFAULT = 10;
/**
* 圆角的大小
*/
private int mBorderRadius; public CycleImageView(Context context)
{
this(context,null);
this.setOnTouchListener(new CustomOnTouchOnGesture());
mPaint = new Paint();
mPaint.setAntiAlias(true);
} public CycleImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
this.setOnTouchListener(new CustomOnTouchOnGesture());
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CycleImageView); mBorderRadius = a.getDimensionPixelSize(
R.styleable.CycleImageView_borderRadius, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
BODER_RADIUS_DEFAULT, getResources()
.getDisplayMetrics()));// 默觉得10dp
Log.e("TAG", mBorderRadius+"");
type = a.getInt(R.styleable.CycleImageView_type, TYPE_CIRCLE);// 默觉得Circle a.recycle();
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 假设类型是圆形。则强制改变view的宽高一致,以小值为准
*/
if (type == TYPE_CIRCLE)
{
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(width, width);
} } //清缓存
@Override
public void invalidate()
{
mWeakBitmap = null;
if (mMaskBitmap != null)
{
mMaskBitmap.recycle();
mMaskBitmap = null;
}
super.invalidate();
} @SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas)
{
//在缓存中取出bitmap
Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get(); if (null == bitmap || bitmap.isRecycled())
{
//拿到Drawable
Drawable drawable = getDrawable();
//获取drawable的宽和高
int dWidth = drawable.getIntrinsicWidth();
int dHeight = drawable.getIntrinsicHeight(); if (drawable != null)
{
//创建bitmap
bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Config.ARGB_8888);
float scale = 1.0f;
//创建画布
Canvas drawCanvas = new Canvas(bitmap);
//依照bitmap的宽高。以及view的宽高,计算缩放比例。由于设置的src宽高比例可能和imageview的宽高比例不同,这里我们不希望图片失真。
if (type == TYPE_ROUND)
{
// 假设图片的宽或者高与view的宽高不匹配。计算出须要缩放的比例。缩放后的图片的宽高。一定要大于我们view的宽高;所以我们这里取大值;
scale = Math.max(getWidth() * 1.0f / dWidth, getHeight()
* 1.0f / dHeight);
} else
{
scale = getWidth() * 1.0F / Math.min(dWidth, dHeight);
}
//依据缩放比例,设置bounds,相当于缩放图片了
drawable.setBounds(0, 0, (int) (scale * dWidth),
(int) (scale * dHeight));
drawable.draw(drawCanvas);
if (mMaskBitmap == null || mMaskBitmap.isRecycled())
{
mMaskBitmap = getBitmap();
}
// Draw Bitmap.
mPaint.reset();
mPaint.setFilterBitmap(false);
mPaint.setXfermode(mXfermode);
//绘制形状
drawCanvas.drawBitmap(mMaskBitmap, 0, 0, mPaint);
mPaint.setXfermode(null);
//将准备好的bitmap绘制出来
canvas.drawBitmap(bitmap, 0, 0, null);
//bitmap缓存起来。避免每次调用onDraw,分配内存
mWeakBitmap = new WeakReference<Bitmap>(bitmap);
}
}
//假设bitmap还存在,则直接绘制就可以
if (bitmap != null)
{
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
return;
} }
/**
* 绘制形状
* @return
*/
public Bitmap getBitmap()
{
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK); if (type == TYPE_ROUND)
{
canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()),
mBorderRadius, mBorderRadius, paint);
} else
{
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2,
paint);
} return bitmap;
} class CustomOnTouchOnGesture implements OnTouchListener, OnGestureListener { GestureDetector myGesture = new GestureDetector(getContext(),this);
View view = null;
int[] temp = new int[] { 0, 0 }; @Override
public boolean onTouch(View v, MotionEvent event) {
//这一步仅仅是我的强迫症而已,由于onTouch事件是不断被调用的
if(view == null)
view = v;
myGesture.onTouchEvent(event);
if(event.getAction()==MotionEvent.ACTION_UP){
Log.d("onTouch", "getRawX: "+event.getRawX()+" getRawY: "+event.getRawY());
}
return true;
} //在按下时调用
@Override
public boolean onDown(MotionEvent e) { temp[0] = (int) e.getX();
temp[1] = ((int) e.getRawY()) - view.getTop();
return false;
} //手指在触摸屏上迅速移动,并松开的动作。
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) { return false;
} //长按的时候调用
@Override
public void onLongPress(MotionEvent e) {
Toast.makeText(getContext(), "你长按了麦麦", Toast.LENGTH_LONG).show(); } //按住然后滑动时调用
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
int x = (int) e2.getRawX();
int y = (int) e2.getRawY();
//设置试图所处的位置
view.layout(x - temp[0], y - temp[1], x + view.getWidth() - temp[0], y - temp[1] + view.getHeight());
return false;
} // 用户轻触触摸屏。尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
// 注意和onDown()的差别,强调的是没有松开或者拖动的状态
@Override
public void onShowPress(MotionEvent e) { } // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
Toast.makeText(getContext(), "你点击了button", Toast.LENGTH_LONG).show();
return false;
}
}
}

主Activity

public class MainActivity extends Activity {
private Button touchButton;
CycleImageView maimaicircle;
CycleImageView maimairound;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
touchButton = (Button) findViewById(R.id.touch_button);
maimaicircle=(CycleImageView)findViewById(R.id.maimaicircle);
maimairound=(CycleImageView)findViewById(R.id.maimairound);
maimairound.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}); touchButton.setOnTouchListener(new CustomOnTouchOnGesture());
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} class CustomOnTouch implements OnTouchListener{
int[] temp = new int[] { 0, 0 };
Boolean ismove = false;
int downX = 0;
int downY = 0; @Override
public boolean onTouch(View v, MotionEvent event) {
int eventaction = event.getAction(); int x = (int) event.getRawX();
int y = (int) event.getRawY(); switch (eventaction) { case MotionEvent.ACTION_DOWN: // touch down so check if the
temp[0] = (int) event.getX();
temp[1] = y - v.getTop();
downX = (int) event.getRawX();
downY = (int) event.getRawY();
ismove = false;
break; case MotionEvent.ACTION_MOVE: // touch drag with the ball
v.layout(x - temp[0], y - temp[1], x + v.getWidth() - temp[0], y - temp[1] + v.getHeight()); if (Math.abs(downX - x) > 10 || Math.abs(downY - y) > 10)
ismove = true;
break;
case MotionEvent.ACTION_UP:
if (!ismove)
Toast.makeText(MainActivity.this, "你点击了这个button!! 。! !。。。。!! ", Toast.LENGTH_LONG).show();
Log.d("MotionEvent.ACTION_UP", "getRawX"+event.getRawX()+" getRawY"+event.getRawY());
break;
}
return false;
}
} /*
* getRawX:触摸点相对于屏幕的坐标
getX: 触摸点相对于view的坐标
getTop: button左上角相对于父view(LinerLayout)的y坐标
getLeft: button左上角相对于父view(LinerLayout)的x坐标
* */
class CustomOnTouchOnGesture implements OnTouchListener, OnGestureListener { GestureDetector myGesture = new GestureDetector(MainActivity.this,this);
View view = null;
int[] value = new int[] { 0, 0 }; @Override
public boolean onTouch(View v, MotionEvent event) {
//这一步仅仅是我的强迫症而已,由于onTouch事件是不断被调用的
if(view == null)
view = v;
myGesture.onTouchEvent(event);
if(event.getAction()==MotionEvent.ACTION_UP){
Log.d("onTouch", "getRawX: "+event.getRawX()+" getRawY: "+event.getRawY());
}
return false;
} //在按下时调用
@Override
public boolean onDown(MotionEvent e) {
value[0] = (int) e.getX();
value[1] = ((int) e.getRawY()) - view.getTop();
return false;
} //手指在触摸屏上迅速移动。并松开的动作。
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
} //长按的时候调用
@Override
public void onLongPress(MotionEvent e) {
Toast.makeText(MainActivity.this, "你长按了button", Toast.LENGTH_LONG).show();
} //按住然后滑动时调用
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
int x = (int) e2.getRawX();
int y = (int) e2.getRawY();
view.layout(x - value[0], y - value[1], x + view.getWidth() - value[0], y - value[1] + view.getHeight());
return false;
} // 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
// 注意和onDown()的差别,强调的是没有松开或者拖动的状态
@Override
public void onShowPress(MotionEvent e) {
} // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
Toast.makeText(MainActivity.this,"麦麦的位置是"+getMaiMaiLocal(), Toast.LENGTH_LONG).show();
return false;
} }
public String getMaiMaiLocal(){
int[] location = new int[2];
maimaicircle.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
return "图片各个角Left:"+maimaicircle.getLeft()+"Right:"+maimaicircle.getRight()+"Top:"+maimaicircle.getTop()+"Bottom:"+maimaicircle.getBottom();
}
}

主XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:wjj="http://schemas.android.com/apk/res/com.wjj.ontouchdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wjj.ontouchdemo.Activity.MainActivity" >
<com.wjj.ontouchdemo.CustomView.CycleImageView
android:id="@id/maimairound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon3"
wjj:type="round"
wjj:borderRadius="20dp">
</com.wjj.ontouchdemo.CustomView.CycleImageView> <Button
android:id="@+id/touch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="快来按我"
android:background="@drawable/shape"/> <com.wjj.ontouchdemo.CustomView.CycleImageView
android:id="@id/maimaicircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:src="@drawable/icon3"
wjj:type="circle" /> </RelativeLayout>

分析:

在做的过程中发如今XML文件里配置好的+id却在Activity中无法获取到他的Id除非自己在R文件里自己加入,为了避免麻烦才有了ids.xml。

全部的触屏的那些操作已经写在了自己定义的ImageView里了,所以没像Button一样在MainActivity中使用内部类来操作。

具体的OnTouchListener, OnGestureListener周期的凝视已经写在上面了。

大体内容就是如此。

那么这样一个图能做什么?

发散思维:

1.相似于加速球那一类的操作都能够

2.应对于特殊的形状要求

源代码地址:http://yunpan.cn/cdRPzseyfw4rr 訪问password deef

创作的过程中有一部分代码參照了网上的样例,如有雷同。请见谅。

Android 自己定义ImageView实现圆角/圆形 附加OnTouchListener具体凝视以及Button圆角的更多相关文章

  1. Android自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示

    Android中的ImageView只能显示矩形的图片,为了用户体验更多,Android实现圆角矩形,圆形或者椭圆等图形,一般通过自定义ImageView来实现,首先获取到图片的Bitmap,然后通过 ...

  2. Android自己定义圆角ImageView

    我们常常看到一些app中能够显示圆角图片.比方qq的联系人图标等等,实现圆角图片一种办法是直接使用圆角图片资源,当然假设没有圆角图片资源.我们也能够自己通过程序实现的,以下介绍一个自己定义圆角Imag ...

  3. Android自己定义圆角ImageView 支持网络图片

    先看下效果图 我们再来看一张CSDN的圆角图片 从布局能够看出csdn app 的头像也是圆角的Image,但能够看到.有明显的毛刺感.不知道是csdn 程序猿的疏忽还是 我手机的问题,本人手机(小米 ...

  4. [Android] 给图像加入相框、圆形圆角显示图片、图像合成知识

        前一篇文章讲述了Android触屏setOnTouchListener实现突破缩放.移动.绘制和加入水印,继续我的"随手拍"项目完毕给图片加入相框.圆形圆角显示图片和图像合 ...

  5. Android ImageView加载圆形图片且同时绘制圆形图片的外部边缘边线及边框

     Android ImageView加载圆形图片且同时绘制圆形图片的外部边缘边线及边框 在Android早期的开发中,如果涉及到圆形图片的处理,往往需要借助于第三方的实现,见附录文章1,2.And ...

  6. android 自己定义水平和圆形progressbar 仅仅定义一些style就能够

    效果图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/diss ...

  7. Android 自己定义UI圆角button

    Android实际开发中我们一般须要圆角的button,普通情况下我们能够让美工做出来对应的button图片.然后放上去就可以,另外我们能够在布局文件里直接设置,也能够达到一样的效果. 以下解说在布局 ...

  8. Android学习笔记之如何使用圆形菜单实现旋转效果...

    PS:最近忙于项目的开发,一直都没有去写博客,是时候整理整理自己在其中学到的东西了... 学习内容: 1.使用圆形菜单并实现旋转效果..     Android的圆形菜单我也是最近才接触到,由于在界面 ...

  9. Android UI--自定义ListView(实现下拉刷新+加载更多)

    Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就 ...

随机推荐

  1. linux之tr

    通过使用 tr,您可以非常容易地实现 sed 的许多最基本功能.您可以将 tr 看作为 sed 的(极其)简化的变体:它可以用一个字符来替换另一个字符,或者可以完全除去一些字符.您也可以用它来除去重复 ...

  2. Replacing Accented characters(Diacritic) .NET

    原文发布时间为:2012-02-17 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Collections.Generic;using Syste ...

  3. [LeetCode] Scramble String 字符串 dp

    Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...

  4. Method, apparatus, and system for speculative abort control mechanisms

    An apparatus and method is described herein for providing robust speculative code section abort cont ...

  5. layui 自定义表单验证 以及提交表单

    订购数量</span> <span style="color: red">*</span>: <input type="text ...

  6. 有道词典中的OCR功能:第三方库的变化

    之前有点好奇有道词典中的OCR功能,具体来说就是强力取词功能.我知道的最有名的OCR库是tesseract,这个库是惠普在早些年前开源的. 在用python做爬虫处理验证码的时候,就会用到这个库,对应 ...

  7. Python 复习-1

    #!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2017/10/27 22:46 # @Author : lijunjiang # @Fi ...

  8. c# Thread类

    现在C#已经建议摈弃使用 Suspend, Resume 暂停/恢复线程, 也尽量少用 Abort方法中断一个线程. 建议使用线程的同步手段有:  Mutex.ManualResetEvent.Aut ...

  9. centos7下配置时间同步服务器

    同网段20几台服务器: 其中有一组mysql 集群中 互为主从 选一台mysql master 作为时间同步的服务器,这样做的好处以便于这台down了 另一个与他互为主从的master 继续提供时间同 ...

  10. android实现多条件筛选列表菜单筛选菜单

    封装组合控件实现一个简单的多条件筛选菜单,可根据自己需求定制筛选条件,动态添加筛选项,灵活使用. 控件封装,点击切换,使用popupWindow实现下拉列表,项目中封装了多种数组数据排序处理方法的工具 ...