android 旋转动画卡顿自定义ImageView旋转发生卡顿现象

1919人阅读
Android UI设计(10)
提起ProgressBar,想必大家都比较熟悉,使用起来也是比较方便,直接在XML文件中引用,然后添加属性,运行就OK了,虽然使用ProgressBar很方便但是在我们开发的每一个应用基本上都有自己的主体风格,如果使用了系统自带的效果图,给人的感觉是和总体风格太不搭配了,看上去很是别扭,我们自己开发也觉得不爽,于是就想着自定义一下效果,其实自定义ProgressBar的效果也不难,大概可分为三步走吧:
一、在anim文件夹下使用animation-list定义动画集
&?xml version=&1.0& encoding=&UTF-8&?&
&animation-list android:oneshot=&false& xmlns:android=&/apk/res/android&&
&item android:duration=&50& android:drawable=&@drawable/circle_10001& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10002& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10003& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10004& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10005& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10006& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10007& /&
&/animation-list&
二、在style.xml文件中定义风格
&style name=&CircleProgressStyle& parent=&@android:style/Widget.ProgressBar.Large&&
&item name=&android:indeterminateDrawable&&@anim/anim_progress_circle&/item&
三、在使用ProgressBar的xml文件中设置其style
&ProgressBar
android:layout_width=&50dip&
android:layout_height=&50dip&
style=&@style/CircleProgressStyle&/&
通过以上步骤,基本上就可以实现自己想要的效果了,这也是我在开发中一直习惯使用的方式,当然了使用其它方式同样可以实现这种效果,今天我主要是想讲一下使用AnimationDrawable 和ImageView结合来实现上述效果,所以以上方法就不再详解了(如果大家想了解其它的方式,留你邮箱,给你回信)。
现在进入正题,首先看一下项目结构
在drawable文件夹下新建circle.xml文件,内容如下:
&?xml version=&1.0& encoding=&UTF-8&?&
&animation-list
android:oneshot=&false&
xmlns:android=&/apk/res/android&&
&item android:duration=&50& android:drawable=&@drawable/circle_10001& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10002& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10003& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10004& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10005& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10006& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10007& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10008& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10009& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10010& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10011& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10012& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10013& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10014& /&
&item android:duration=&50& android:drawable=&@drawable/circle_10015& /&
&/animation-list&
在main.xml文件中做简单布局,没什么需要注释和解释的,你一看就懂,内容如下:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout
xmlns:android=&/apk/res/android&
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:background=&#ffffff&&
&ImageView
android:id=&@+id/imageview&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_gravity=&center&
android:src=&@drawable/circle& /&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:onClick=&start&
android:text=&旋转& /&
&/LinearLayout&
在MainActivity中实现的代码:
public class MainActivity extends Activity {
private ImageView imageV
private AnimationDrawable animationD
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initWedgits();
* 初始化各组件
private void initWedgits() {
imageView = (ImageView) findViewById(R.id.imageview);
animationDrawable = (AnimationDrawable) imageView.getDrawable();
} catch (Exception e) {
e.printStackTrace();
public void start(View view) {
animationDrawable.start();
} catch (Exception e) {
e.printStackTrace();
代码编写完成后运行程序,在没有点击按钮时ImageView显示一张静态图,当点击按钮后,就可以实现图片的旋转了,效果如下:
(忘记做了动画效果图,呜呜......以后补上)
可以看到只要我们点击了按钮,图片就搁在那一直旋转,是不是很神奇?赶脚和ProgressBar的效果一样,而且不用再在style.xml文件中定义样式了,顿时感觉这种方法比使用ProgressBar好了点(自恋中,(*^__^*) 嘻嘻……不要扔砖哦),但是细心的童靴就会发现一个问题,为什么把animationDrawable.start()方法放到start()方法中呢?为什么不直接放到initWedgits() 中呢?那好,为了打消大家的疑虑,现在我就把在start()方法中的代码注释掉,直接把animationDrawable.start()放到initWedgits()方法中,修改代码如下:
public class MainActivity extends Activity {
private ImageView imageV
private AnimationDrawable animationD
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initWedgits();
* 初始化各组件
private void initWedgits() {
imageView = (ImageView) findViewById(R.id.imageview);
animationDrawable = (AnimationDrawable)imageView.getDrawable();
animationDrawable.start();
} catch (Exception e) {
e.printStackTrace();
public void start(View view) {
// animationDrawable.start();
} catch (Exception e) {
e.printStackTrace();
这时候,你一定会想,运行之后不论点击不点击按钮(实际上你把按钮点烂,图片都不会转滴,因为我把它注释掉了,(*^__^*) 嘻嘻……)图片都会旋转,嗯,我们运行一下程序,结果你会发现图片并没有像我们想象中的那样旋转。咦?奇了怪了,图片怎么不旋转呢?是不是哪写错了,于是从头到尾检查了一遍代码,当确定了代码没有问题之后,你就郁闷了,估计会想是不是因为没有刷新的缘由呀(我刚开始就是这样想的,呜呜~~~~(&_&)~~~~
)?于是赶紧使用了View的刷新方法,把所有的都试了,图片还是不能旋转,你就更郁闷了,怎么会这样呢?是不是在onCreate方法中不能这样调用animationDrawable.start()?于是又尝试了把animationDrawable.start()方法放入到onResume()方法中,但结果图片还是不旋转,最后使用了最后一招又把该代码放入到onWindowFocusChanged(boolean hasFocus)方法中,这样一试,图片终于旋转了,呵呵,好开心呀,这时候你会很开心,因为以后使用的话直接在onWindowFocusChanged(boolean
hasFocus)方法中调用animationDrawable的start()方法就行了,不再需要利用其它的事件来触发图片的旋转了,紧接着你估计就会想了为什么animationDrawable的start()方法非得放到这里才会执行了呢?出于习惯你应该会想到去找官方文档查看一下,找呀找呀找呀,终于找到了,官方文档的说明截个图如下:
哦,原来是这样,大致意思就是说不要在onCreate方法中调用AnimationDrawable的start()方法,因为此时的AnimationDrawable还没有完全附加到视图窗口上,如果想你想立即播放动画而不想用事件来触发的话(就是最开始我们使用的在start()方法中调用AnimationDrawable的start()方法),你就需要在onWindowFocusChanged(boolean
hasFocus)方法中来调用AnimationDrawable的start()方法了,看完了官方文档,就知道以后怎么使用了,嘻嘻,再次高兴一下......
老习惯,贴一下代码
public class MainActivity extends Activity {
private ImageView imageV
private AnimationDrawable animationD
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initWedgits();
* 初始化各组件
private void initWedgits() {
imageView = (ImageView) findViewById(R.id.imageview);
animationDrawable = (AnimationDrawable) imageView.getDrawable();
} catch (Exception e) {
e.printStackTrace();
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);&/p&&p&
if(hasFocus)
animationDrawable.start();
public void start(View view) {
//animationDrawable.start();
} catch (Exception e) {
e.printStackTrace();
另外,我尝试了从网上看到的另外几种方法,其中一个简单的实现就是在imageView的post()方法中调用AnimationDrawable的start()方法而不需要在onWindowFocusChanged(boolean hasFocus)方法中调用,测试了一下果然有效,至于其他的实现方式就不再贴出代码了,如果谁有兴趣可以自己动手问问度娘,毕竟自己动手,丰衣足食嘛,呵呵
好了,到此为止使用ImageView和AnimationDrawable结合的方式实现ProgressBar效果讲解完毕,感谢您的阅读
第一次发帖,如有不足,请指正
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:112718次
积分:1499
积分:1499
排名:千里之外
原创:30篇
评论:71条
(1)(1)(1)(3)(3)(1)(1)(1)(2)(4)(4)(1)(1)(5)(1)标签:至少1个,最多5个
越来越多的社交软件通过圆形外框来展现用户头像,因此我们需要将方形源文件以圆形来展示。
实现 src 圆形化显示
完整代码:
public class CircleImageView extends ImageView {
private static final String TAG = "CircleImageView";
private Shader mS
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleImageView(Context context) {
super(context);
protected void onDraw(Canvas canvas) {
Bitmap rawBitmap = getBitmap(getDrawable());
if (rawBitmap != null) {
int viewWidth = getWidth();
int viewHeight = getHeight();
int viewMinSize = Math.min(viewWidth, viewHeight);
if (mShader == null) {
mShader = new BitmapShader(rawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
float radius = viewMinSize / 2.0f;
canvas.drawCircle(radius, radius, radius, mPaint);
super.onDraw(canvas);
private Bitmap getBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof ColorDrawable) {
Rect rect = drawable.getBounds();
int width = rect.width();
int height = rect.height();
int color = ((ColorDrawable) drawable).getColor();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color),
Color.blue(color));
onDraw() 方法部分注释:
protected void onDraw(Canvas canvas) {
// 通过 getBitMap 方法获取到原始 Bitmap
Bitmap rawBitmap = getBitmap(getDrawable());
// Drawable 是 Bitmap 或 Color
if (rawBitmap != null) {
int viewWidth = getWidth();
int viewHeight = getHeight();
// 由于是圆形,所以需要两者中的 Min。
int viewMinSize = Math.min(viewWidth, viewHeight);
// 判断 Shader 是否已经初始化过,避免绘制过程卡顿。
if (mShader == null) {
// 把原始 Bitmap 给 Shader,模式为拉伸。
mShader = new BitmapShader(rawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
// 得到圆形半径
float radius = viewMinSize / 2.0f;
// 确定绘制 Circle 的中心点、半径和 Paint
canvas.drawCircle(radius, radius, radius, mPaint);
super.onDraw(canvas);
getBitmap() 方法部分注释:
private Bitmap getBitmap(Drawable drawable) {
// 如果是 Bitmap 类的 Drawable
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof ColorDrawable) {
Rect rect = drawable.getBounds();
int width = rect.width();
int height = rect.height();
int color = ((ColorDrawable) drawable).getColor();
// 创建 ARGB_8888 格式的 Bitmap
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
// 绘制目标颜色,从而把颜色转换为 Bitmap
canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color),
Color.blue(color));
存在的问题:
对图片资源不会自动缩放,如果是用户自行上传的图片则可能造成资源浪费或者 OOM,但本次需求是系统自带的图标圆形化,所以不需要实现。如果需要实现则可以用 Matrix 实现,可以见文末参考处;
如果需要加上背景,那么 Background 依然是方形的,而不是圆形。
references:
0 收藏&&|&&0
你可能感兴趣的文章
1 收藏,1.3k
1 收藏,158
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
我要该,理由是:2283人阅读
实习android开发之路(298)
分类:&&1090人阅读&&&
众所周知,想要让ImageView旋转的话,可以用setRotation()让其围绕中心点旋转,但这个旋转是不带动画的,也就是旋转屏幕时图片噌的一下就转过去了,看不到旋转的过程,此UI体验不大好,为此需要自定义带旋转动画的ImageView.虽然Google SDK里基本控件里没有,但在Camera的原生APP代码里却给出了带旋转动画的ImageView,即今天的主角:RotateImageView。
尽管民间已有&&&提供思路实现带旋转动画的ImageView,都不如Google官方标配的啊。先上源码吧,为实现此目的,需要四个文件:
1、Rotatable.java
他就是个接口,里面有setOrientation这个方法。Google这么写是因为有大量自定义UI都要继承这个接口。
2、TwoStateImageView.java
在ImageView的基础上增加了mFilterEnabled这个属性,开关打开后,通过改变图片的Alpha实现两种状态,默认这个开关是开的,图片透明度为255,即不透明。
3、RotateImageView.java
整体没啥可说的,在setBitmap处有四句代码运行不正确我给换成了固定值。这个setBitmap干啥呢?是为了实现在同一个ImageView切换图片时的淡入淡出效果,如果单纯是旋转则不需要这个函数。不过本文的测试代码还是对这一功能做了测试。其思想也很简单,用Drawable[] mThumbs来存两个缩略图,第一次set的时候缩略图存一张,第二次再set的时候再放数组里一张,然后将Drawable[]数组实例化到TransitionDrawable变量里,通过这个变量的startTransition()显示淡入淡出效果,里面的参数表示时间。如果设成1000毫秒即1秒则会非常明显。关于TransitionDrawable的更多用法和解释可以参见&
4、有了以上三个文件其实已经可以完成旋转ImageView了,在布局里定义成RotateImageView即可。但仍需要角度。下面这个函数是将连续的旋转角度0---360度变换成0°、90°、180°、270°四个值。我们旋转屏幕时,当成一定角度时才旋转图片,而不是稍微动一下就旋转,除非需求如此。
下面就要解决如何获得屏幕旋转角度的问题。最初我也想着用onConfigurationChanged()但发现这就是扯淡,这个只能检测此时处在横屏还是竖屏。后面再交代其用法。最终是用OrientationEventListener监测的。
MainActivity.java代码如下:
布局如下:activity_main.xml
运行效果: 下图是初始界面,三幅图,前两个是RotateImageView,第三个是一般的ImageView.可以看出当RoteteImageView设置不使用动画时,其旋转效果和ImageView的setRotation是一样的。第一幅图和第二图的差别,第一图南怀瑾先生的,四周不带透明区域,第二幅图我用ps做了四周的透明处理。
如果不使用文中的Util.roundOrientation()函数,即有个角度就让它转,如果它的四周没有透明区域的话将会看到下图:
(抱歉,截图不是一次截的,但效果是真实的,此图周四晚截得)
下面这幅图是用大中兴的geek牛逼的连续拍照拍下来的,记录了四周不带透明区域旋转时图片变形的场景:
第一副图片里的淡入淡出测试按钮大家自己按看效果,太晚了不传图了。
------------------本文系原创,转载注明作者:yanzi1225627
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4704594次
积分:40079
积分:40079
排名:第97名
原创:22篇
转载:1920篇
评论:507条
(37)(13)(28)(148)(78)(74)(36)(80)(90)(41)(139)(241)(117)(357)(181)(63)(56)(57)(5)(47)(1)(30)(23)设置ImageView的图片资源是直接来自SD卡 - 短裤党 - ITeye博客
博客分类:
在设置ImageView资源的时候,这时的图片是来自SD卡,查看API很容易就会看到view.setImageUri(Uri u)这个函数。所以一般会这样写:
ImageView view = (ImageView)findViewById(...);
File file = new File(path);
Uri uri = Uri.from(file);
view.setImageUri(uri);
但是这样做是不行的,因为setImageUri这个函数使不能读取SD卡中的文件的,只能读取手机本身的文件。
所以改用以下这种方式:
Bitmap bit = BitmapFactory.decodeFile("/sdcard/image/test.jpg"); //自定义//路径
iv.setImageBitmap(bit);&
用这种方式的时候,如果图片太大,很可能会出现这样的bug:
Java.lang.OutOfMemoryError : bitmap size exceeds VM budget
解决方法是:
FileInputStream f = new FileInputStream(path);
Bitmap bm =
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;//图片的长宽都是原来的1/8
BufferedInputStream bis = new BufferedInputStream(f);
bm = BitmapFactory.decodeStream(bis, null, options);
view.setImageBitmap(bm);
gundumw100
浏览: 4143408 次
来自: 上海
本地lua脚本终于执行成功了,虽然不是通过redis
大神://处理返回的接收状态
这个好像没有监听到
拦截部分地址,怎么写的for(int i=0;i&lis ...
Android控件之带清空按钮(功能)的AutoComplet ...
希望有表例子更好。。。,不过也看明白了。android学习记录UI篇-----imageView实现图片的旋转和缩放
感觉在代码中写出解析会比较好看,我直接在程序代码中解析所用的方法吧。
MainActivity:
package com.example.imageview_demo03;
import android.support.v7.app.ActionBarA
import android.util.DisplayM
import android.annotation.SuppressL
import android.graphics.B
import android.graphics.M
import android.graphics.drawable.BitmapD
import android.os.B
import android.widget.ImageV
import android.widget.LinearL
import android.widget.SeekB
import android.widget.TextV
import android.widget.SeekBar.OnSeekBarChangeL
@SuppressLint("NewApi")
public class MainActivity extends ActionBarActivity implements OnSeekBarChangeListener{
//最小的缩放宽度
private int minWidth = 80;
private ImageView imageV
private SeekBar seekBar1;
private SeekBar seekBar2;
private TextView textView1;
private TextView textView2;
//矩阵类,用于对图像进行旋转
private Matrix matrix = new Matrix();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView)findViewById(R.id.imageView);
seekBar1 = (SeekBar)findViewById(R.id.seekBar1);
seekBar2 = (SeekBar)findViewById(R.id.seekBar2);
seekBar1.setOnSeekBarChangeListener(this);
seekBar2.setOnSeekBarChangeListener(this);
textView1 = (TextView)findViewById(R.id.textview1);
textView2 = (TextView)findViewById(R.id.textview2);
//创建一个空的展示矩阵,用于存储当前屏幕信息,如大小。
DisplayMetrics displayMetrics = new DisplayMetrics();
//把当前管理的屏幕尺寸传递给displayMetrics
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
//设置放大的最大值不超过屏幕大小
seekBar1.setMax(displayMetrics.widthPixels-minWidth);
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (seekBar.getId()==R.id.seekBar1) {
//设置宽度为80到最大
int mwidth = progress+minW
int mheight = (int)(2*mwidth/3);
//设置imageView的输出大小参数
//因为图片是fitcenter参数,所以图片会随着image框架的大小变化而变化
//从而改变image框架的大小会引起图片大小的变化,实现图片的放大缩小功能
imageView.setLayoutParams(new LinearLayout.LayoutParams(mwidth, mheight));
textView1.setText("图片宽度:"+mwidth+"\t图片高度:"+mheight);
}else if (seekBar.getId()==R.id.seekBar2) {
//imageView自身的setRotation方法是绕图的中心顺时针防线旋转
//同时该旋转不会改变imageView的输出大小,所超出imageView的部分会照常显示在所跨越视图的下方
//imageView.setRotation(progress);
//如果想创建一个不超出imageView输出框架的旋转图像,那么需要把原图像取出,把原图像进行旋转,重新放入到imageView中
//缺陷:占用较多的内存,会比较卡
Bitmap bitmap = ((BitmapDrawable)(getResources().getDrawable(R.drawable.photo))).getBitmap();
matrix.setRotate(progress);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
imageView.setImageBitmap(bitmap);
textView2.setText("图片旋转"+progress+"度");
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
运行图例:
如果文中有不妥或你有更好的方法,欢迎交流。

我要回帖

更多关于 android 旋转动画卡顿 的文章

 

随机推荐