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

平时要用一些非方方正正的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. TextBox取不到值及其TextBox取不到js赋的值

    原文发布时间为:2009-10-22 -- 来源于本人的百度文章 [由搬家工具导入] 原因:使用了一个只读的TextBox控件 曾经遇到过这样的问题:使用了一个只读的TextBox控件,但是在后台代码 ...

  2. bzoj 2115 [Wc2011] Xor 路径最大异或和 线性基

    题目链接 题意 给定一个 \(n(n\le 50000)\) 个点 \(m(m\le 100000)\) 条边的无向图,每条边上有一个权值.请你求一条从 \(1\)到\(n\)的路径,使得路径上的边的 ...

  3. Qualcomm 專業名詞

    APSS Application processor subsystem software BAM Bus Access Manager blsp BAM low speed peripheral T ...

  4. java中Map的entrySet 和keySet的使用

    存储这样的一个数据关系结构  使用嵌套map存储 可以通过调用  entrySet方法  或者 keySet方法 进行迭代或者增强for循环 便利输出 这里演示 迭代器的方式进行遍历 package ...

  5. 数据库索引实现原理—B_TREE

    数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询.更新数据库表中数据.索引的实现通常使用B_TREE.B_TREE索引加速了数据访问,因为存储引擎不会再去扫描整张表得到需要的数据:相反 ...

  6. 暂停时间 以及dict 循环

    暂停时间 #!/usr/bin/python # -*- coding: UTF-8 -*- import time myD = {1: 'a', 2: 'b'} for key, value in ...

  7. z-index 基础详解

    关于z-index网上其实有不少博文,写得也不错,不过有些帖子比较旧,而IE也已经更新到了IE11了,所以还是重新总结一下.由于 z-index 的属性表现和层级有关,有些特点在某些层级下才表现出来, ...

  8. webservice测试窗体只能用于来自本地计算机的请求

    写在前面 在编写好webservice后,发布到iis服务器,你会发现会有这样的异常“测试窗体只能用于来自本地计算机的请求”. 解决方案 在web.config中添加以下代码即可解决问题 <we ...

  9. Jsp2.0自定义标签(第一天)——一个简单的例子

    今天是学习自定义标签的第一天 Jsp2.0以来,自定义标签的实现比传统标签的实现容易了很多,一般只要extends类SimpleSupport重写doTag()方法即可. 先看最简单的例子,输出一个H ...

  10. 安卓Webview缓存网页数据(无网络正常显示)

    热度 1已有 52 次阅读2016-8-26 17:53 |个人分类:常见问题|系统分类:移动开发 一.需求经历 最近的项目是一个原生 +webview 显示的 APP,一开始的时候,网站那边要求我们 ...