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

平时要用一些非方方正正的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. 洛谷 [P2341] 受欢迎的牛

    强连通分量 一个结论: 在有向图中, 一个联通块能被所有点遍历当且仅当图中只有一个连通块出度为零 #include <iostream> #include <cstdio> # ...

  2. 网页制作教程:td也可以溢出隐藏显示【转】

    原文发布时间为:2010-02-05 -- 来源于本人的百度文章 [由搬家工具导入] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stri ...

  3. javascript实现可拖动DIV层

    原文发布时间为:2009-05-04 -- 来源于本人的百度文章 [由搬家工具导入] 注意以下红色部分是关键.如果不使用      document.documentElement,而使用docume ...

  4. SQLServer Split

    ALTER FUNCTION dbo.splitl ( @String VARCHAR(MAX), @Delimiter VARCHAR(MAX) ) RETURNS @temptable TABLE ...

  5. android基本控件学习-----Button

    Button讲解: 一.在我们实际的使用button的时候经常会对button不同状态会有不同的显示,在讲解Button前,首先对drawable下面的statelistdrawable的相关知识讲一 ...

  6. mybatis hashmap 输入键值对为空时,key 丢失

    参考文档:https://blog.csdn.net/lulidaitian/article/details/70941769 springMVC+mybatis查询数据,返回resultType=” ...

  7. Cryptography I 学习笔记 --- 密钥交换

    1. 使用可信第三方(Trusted third parties)进行密钥交换. a. Alice与TTP之间的密钥是K1,Bob与TTP之间的密钥是K2. b. Alice向TTP发起一个与Bob交 ...

  8. 源码分析——迁移学习Inception V3网络重训练实现图片分类

    1. 前言 近些年来,随着以卷积神经网络(CNN)为代表的深度学习在图像识别领域的突破,越来越多的图像识别算法不断涌现.在去年,我们初步成功尝试了图像识别在测试领域的应用:将网站样式错乱问题.无线领域 ...

  9. java数据结构和算法10(堆)

    这篇我们说说堆这种数据结构,其实到这里就暂时把java的数据结构告一段落,感觉说的也差不多了,各种常见的数据结构都说到了,其实还有一种数据结构是“图”,然而暂时对图没啥兴趣,等有兴趣的再说:还有排序算 ...

  10. POJ 1239 Increasing Sequences [DP]

    题意:略. 思路:进行两次dp. 第一次dp从前向后,用dp[x]表示从第x位向前dp[x]位可构成一个数字,且与前面的数组符合题意要求.最后求的dp[n]即为最后一个数字的长度. 而题目还有要求,所 ...