Canvas的实际使用
2017-09-10 10:46
190 查看
这个就是一个大致的实现效果,左右滑动用的是一个自定义的HorizontalScrollView,图片渐变用的是一个自定义Drawable;
1、自定义HorizontalScrollView实现实现左右滑动
1.1、extends HorizontalScrollView 并进行相应的初始化
public class GallaryHorizonalScrollView extends HorizontalScrollView implements View.OnTouchListener { private LinearLayout container; private int iconWidth; private int centerX; public GallaryHorizonalScrollView(Context context) { this(context, null); } public GallaryHorizonalScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GallaryHorizonalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { //在ScrollView里面放置一个水平线性布局,再往里面放置很多的ImageView LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT ); container = new LinearLayout(getContext()); container.setLayoutParams(params); setOnTouchListener(this); } }
1.2、重写onLayout方法进行摆放
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //得到某一张图片的宽度 View v = container.getChildAt(0); iconWidth = v.getWidth(); //得到中间x坐标 centerX = getWidth() / 2; //处理中心坐标改成中心图片的左边界 centerX = centerX - iconWidth / 2; //给LinearLayout和HorizontalScrollView之间设置边框距离 container.setPadding(centerX, 0, centerX, 0); }
1.3、设置setOnTouchListener进行事件处理
@Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { //处理移动 //渐变图片 reveal(); } return false; } private void reveal() { //渐变效果 //得到HorizontalScrollView滑出去的距离 int scrollX = getScrollX(); //找到两张渐变的图片的下标--左 右 int indexLeft = scrollX / iconWidth; int indexRight = indexLeft + 1; //设置图片的level for (int i = 0; i < container.getChildCount(); i++) { if (i == indexLeft || i == indexRight) { //变化 //比例 float ratio = 5000f / iconWidth; ImageView ivLeft = (ImageView) container.getChildAt(indexLeft); //scrollX%icon_width:代表滑出去的距离 //滑出去了icon_width/2 icon_width/2%icon_width ivLeft.setImageLevel((int) (5000 - scrollX % iconWidth * ratio)); //右边 if (indexRight < container.getChildCount()) { ImageView ivRight = (ImageView) container.getChildAt(indexRight); //scrollX%icon_width:代表滑出去的距离 //滑出去了icon_width/2 icon_width/2%icon_width ivRight.setImageLevel( (int) (10000 - scrollX % iconWidth * ratio) ); } } else { //灰色 ImageView iv = (ImageView) container.getChildAt(i); iv.setImageLevel(0); } } }
这里只需要对ACTION_MOVE进行处理,对应的提供了一个添加图片数据源的方法;
/** * 添加图片 * * @param revealDrawables 传入的Drawable数组资源 */ public void addImageViews(Drawable[] revealDrawables) { for (int i = 0; i < revealDrawables.length; i++) { ImageView img = new ImageView(getContext()); img.setImageDrawable(revealDrawables[i]); container.addView(img); if (i == 0) { img.setImageLevel(5000); } } addView(container); }
2、自定义Drawable对图片进行处理
图片的渐变效果其实利用了Canvas的裁剪,将画布裁剪成两个区域,左边为未选状态,右边为已选状态,根据滑动的距离去做相应的显示;
public class RevealDrawable extends Drawable { //未被选 private Drawable mUnselectedDrawable; //被选 private Drawable mSelectedDrawable; //显示方向 private int mOrientation; //横向 public static final int HORIZONTAL = 1; //纵向 public static final int VERTICAL = 2; //绘制和裁剪的矩形区域 private final Rect mTmpRect = new Rect(); public RevealDrawable(Drawable unselected, Drawable selected, int orientation) { mUnselectedDrawable = unselected; mSelectedDrawable = selected; mOrientation = orientation; } @Override public void draw(Canvas canvas) { //绘制 int level = getLevel();//from 0 (minimum) to 10000 //右边区域和左边区域--设置成灰色 if (level == 10000 || level == 0) { mUnselectedDrawable.draw(canvas); } else if (level == 5000) { //全部选中 设置成彩色 mSelectedDrawable.draw(canvas); } else { //混合效果的Drawable /** * 将画板切割成两块--左边和右边 */ Rect r = mTmpRect; //得到当前自身Drawable的矩形区域 Rect bounds = getBounds(); { //先绘制灰色部分 level 0--5000--10000 //比例 float ratio = (level / 5000f) - 1f; int w = bounds.width(); if (mOrientation == HORIZONTAL) { w = (int) (w * Math.abs(ratio)); } int h = bounds.height(); if (mOrientation == VERTICAL) { h = (int) (h * Math.abs(ratio)); } int gravity = ratio < 0 ? Gravity.LEFT : Gravity.RIGHT; //从一个已有的bounds矩形边界范围中抠出一个矩形r Gravity.apply( gravity,//从左边还是从右边开始抠 w,//目标矩形的宽度 h,//目标矩形的高度 bounds,//被抠出来的rect r//目标rect ); //保存当前画布 canvas.save(); //进行切割 canvas.clipRect(r); //进行绘制 mUnselectedDrawable.draw(canvas); //恢复之前的画布 canvas.restore(); } { //绘制彩色部分 level 0--5000--10000 //比例 float ratio = (level / 5000f) - 1f; int w = bounds.width(); if (mOrientation == HORIZONTAL) { w -= (int) (w * Math.abs(ratio)); } int h = bounds.height(); if (mOrientation == VERTICAL) { h -= (int) (h * Math.abs(ratio)); } int gravity = ratio < 0 ? Gravity.RIGHT : Gravity.LEFT; //从一个已有的bounds矩形边界范围中抠出一个矩形r Gravity.apply( gravity,//从左边还是从右边开始抠 w,//目标矩形的宽度 h,//目标矩形的高度 bounds,//被抠出来的rect r//目标rect ); //保存当前画布 canvas.save(); //进行切割 canvas.clipRect(r); //进行绘制 mSelectedDrawable.draw(canvas); //恢复之前的画布 canvas.restore(); } } } @Override protected void onBoundsChange(Rect bounds) { //定义好两个Drawable图片的宽高--边界bounds mUnselectedDrawable.setBounds(bounds); mSelectedDrawable.setBounds(bounds); } @Override public int getIntrinsicWidth() { //得到Drawable的实际宽度 return Math.max(mSelectedDrawable.getIntrinsicWidth(), mUnselectedDrawable.getIntrinsicWidth()); } @Override public int getIntrinsicHeight() { //得到Drawable的实际高度 return Math.max(mSelectedDrawable.getIntrinsicHeight(), mUnselectedDrawable.getIntrinsicHeight()); } @Override protected boolean onLevelChange(int level) { //当设置level的时候就会回调该方法 //进行重新绘制 invalidateSelf(); return true; } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.UNKNOWN; } }
3、使用
public class MainActivity extends AppCompatActivity { private int[] mImgIds = new int[] { //7个 R.mipmap.avft, R.mipmap.box_stack, R.mipmap.bubble_frame, R.mipmap.bubbles, R.mipmap.bullseye, R.mipmap.circle_filled, R.mipmap.circle_outline, R.mipmap.avft, R.mipmap.box_stack, R.mipmap.bubble_frame, R.mipmap.bubbles, R.mipmap.bullseye, R.mipmap.circle_filled, R.mipmap.circle_outline }; private int[] mImgIds_active = new int[] { R.mipmap.avft_active, R.mipmap.box_stack_active, R.mipmap.bubble_frame_active, R.mipmap.bubbles_active, R.mipmap.bullseye_active, R.mipmap.circle_filled_active, R.mipmap.circle_outline_active, R.mipmap.avft_active, R.mipmap.box_stack_active, R.mipmap.bubble_frame_active, R.mipmap.bubbles_active, R.mipmap.bullseye_active, R.mipmap.circle_filled_active, R.mipmap.circle_outline_active }; public Drawable[] revealDrawables; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); } private void initView() { for (int i = 0; i < mImgIds.length; i++) { RevealDrawable rd=new RevealDrawable( getResources().getDrawable(mImgIds[i]), getResources().getDrawable(mImgIds_active[i]), RevealDrawable.HORIZONTAL ); revealDrawables[i]=rd; } GallaryHorizonalScrollView hsv = (GallaryHorizonalScrollView) findViewById(R.id.hsv); hsv.addImageViews(revealDrawables); } private void initData() { revealDrawables=new Drawable[mImgIds.length]; } }
源码地址:
http://download.csdn.net/download/wangwo1991/9971873
相关文章推荐
- Canvas的实际使用--自定义搜索效果
- Android PorterDuff.Mode与Canvas实际使用
- 使用 Canvas 的Xfermode 实现 ImageView 圆形图片的实际步骤
- 使用Canvas、Bitmap时易犯的内存泄露问题
- android canvas\paint\path简单使用(自定义view必学)
- Windows Azure Storage (23) 计算Azure VHD实际使用容量
- android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录(原创)
- 使用canvas实现仿新浪微博头像截取上传功能
- 【JAVA实例】代码生成器的原理讲解以及实际使用
- 使用canvas实现带圆点的进度条
- 学习用Node.js和Elasticsearch构建搜索引擎(6):实际项目中常用命令使用记录
- 使用canvas实现仿新浪微博头像截取上传功能
- canvas save()和canvas restore()状态的保存和恢复使用方法及实例
- [置顶] sqlmap 使用测试初级教程(实际已测试 -版本1.0)
- ros_indigo使用keyboard键盘控制虚拟或实际机器人
- flume的级别的架构使用--实际场景应用--可以用于分布式的服务形式的日志采集
- canvas第一次使用
- 面向对象方法和结构化方法比较,形式化方法的实际运用困难,及如何结合使用这三种
- Paint、Canvas、Matrix使用讲解(一、Paint)
- 使用 jquery获取canvas对象报错