自定义控件在Android开发中有着大量的运用,为了做出符合项目的效果很多时候需要自定义控件,这里就使用两个自定义控件,来说明自定义控件的使用流程

仿QQ侧滑

之前使用DrawerLayoutNavigationView都实现了侧滑的效果,在这里使用自定义的View完成相同的效果

这里考虑到的是继承HorizontalScrollView,复写里面的onMeasure方法,设置滑动菜单和主菜单的宽度设置,复写onLayout方法,按照需求摆放子控件,复写onTouchEvent方法,控制移动距离,复写onScrollChanged方法,控制滑动时候的动画

布局

<?xml version="1.0" encoding="utf-8"?>
<com.cj5785.customviewtest.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_orange_light"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/holo_green_light"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"/>
</LinearLayout> </com.cj5785.customviewtest.SlidingMenu>

自定义控件

public class SlidingMenu extends HorizontalScrollView {
private int mScreenWidth;
private ViewGroup mMenu;
private ViewGroup mMain;
private int mMenuWidth;
private boolean isOnce;
private float downX; public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
//得到屏幕宽度
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//只测量一次
if (!isOnce) {
//获得侧滑菜单和主菜单
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(0);
mMain = (ViewGroup) wrapper.getChildAt(1);
//得到宽度,为了体验效果,这里一般会设置menu的right padding宽度
mMenuWidth = mScreenWidth - mScreenWidth / 5;
mMenu.getLayoutParams().width = mMenuWidth;
mMain.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
//开始绘制的时候,向右滑动一段距离
this.scrollTo(mMenuWidth, 0);
isOnce = true;
}
super.onLayout(changed, l, t, r, b);
} @Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//按下时的位置
downX = ev.getX();
break;
case MotionEvent.ACTION_UP:
//松开后滑动的距离,滑动距离小于屏幕的四分之一则回到原位置
float dx = ev.getX() - downX;
if (dx < mScreenWidth / 4) {
this.smoothScrollTo(mMenuWidth, 0);
} else {
this.smoothScrollTo(0, 0);
}
return true;
}
return super.onTouchEvent(ev);
} //当滑动开始时候会调用onScrollChanged()
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
//在这里设置动画
//滑动百分比
float factor = (float) l / mMenuWidth;
//1.平移效果
mMenu.setTranslationX(mMenuWidth * factor * 0.7F);
//2.缩放效果
mMenu.setScaleX(1 - 0.4F * factor);
mMenu.setScaleY(1 - 0.4F * factor);
mMain.setScaleX(0.9F + 0.1F * factor);
mMain.setScaleY(0.9F + 0.1F * factor);
//3.透明度效果
mMenu.setAlpha(1 - factor);
mMain.setAlpha(0.8F + 0.2F * factor);
super.onScrollChanged(l, t, oldl, oldt);
}
}

实现效果如下

实现条目侧滑的效果

在QQ中,还有个功能是比较棒的,那就是条目侧滑,那么要怎么实现条目侧滑效果呢

这里我们使用自定义LinearLayout来实现,其滑动效果通过Scroller来控制

使用dispatchTouchEvent()来记录DOWN,MOVE,UP事件响应的参数,滑动过程中不断调用computeScroll()移动控件位置,使得其形成动画效果,由于要控制滑动距离,就需要动态测量出滑出的距离,复写onFinishInflate()得到距离

布局很简单,就是两个TextView

<?xml version="1.0" encoding="utf-8"?>
<com.cj5785.customviewtest.SlidingItemMenuLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/holo_green_light"
android:gravity="center"
android:text="This is a item"
android:textSize="32sp" /> <TextView
android:layout_width="100dp"
android:layout_height="80dp"
android:background="@android:color/holo_red_light"
android:gravity="center"
android:text="删除"
android:textSize="32sp" /> </com.cj5785.customviewtest.SlidingItemMenuLayout>

然后是自定义控件

public class SlidingItemMenuLayout extends LinearLayout {
private Scroller mScroller;
private float startX;
private float startY;
private float dx;
private float dy;
private View rightChild; public SlidingItemMenuLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
//用来设置松开回弹
mScroller = new Scroller(getContext(), new AccelerateInterpolator(), true);
} //绘制完成后调用
@Override
protected void onFinishInflate() {
super.onFinishInflate();
rightChild = getChildAt(1);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录按下时位置
startX = ev.getX();
startY = ev.getY();
//按下以后拦截事件,交由父类处理
super.dispatchTouchEvent(ev);
return true;
case MotionEvent.ACTION_MOVE:
dx = ev.getX() - startX;
dy = ev.getY() - startY;
//系统能检测到的最小距离
if (Math.abs(dx) - Math.abs(dy) > ViewConfiguration.getTouchSlop()) {
//向左滑动距离不能大于最右边,且向右滑动距离不能大于零
if (getScrollX() + (-dx) > rightChild.getWidth()
|| getScrollX() + (-dx) < 0) {
return true;
}
//滑动一段距离,重新记录位置,拦截滑动事件
scrollBy((int) -dx, 0);
startX = ev.getX();
startY = ev.getY();
return true;
}
break;
case MotionEvent.ACTION_UP:
//得到松手时的偏移量,超过一半则全部显示,否则不显示
int offset = getScrollX() / (float) rightChild.getWidth() > 0.5 ?
rightChild.getWidth() - getScrollX() : -getScrollX();
//初始化滑动参数
mScroller.startScroll(getScrollX(), getScrollY(), offset, 0);
//重新绘制测量,此时会调用computeScroll()方法
invalidate();
//参数重新赋值
startX = 0;
startY = 0;
dx = 0;
dy = 0;
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
} //开启滑动以后,就会不断调用此方法
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}
}

实现效果如下

高级UI-自定义控件的更多相关文章

  1. firefox 扩展开发笔记(三):高级ui交互编程

    firefox 扩展开发笔记(三):高级ui交互编程 前言 前两篇链接 1:firefox 扩展开发笔记(一):jpm 使用实践以及调试 2:firefox 扩展开发笔记(二):进阶开发之移动设备模拟 ...

  2. Android 高级UI设计笔记07:RecyclerView 的详解

    1. 使用RecyclerView       在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...

  3. iOS开发——高级UI&带你玩转UITableView

    带你玩装UITableView 在实际iOS开发中UITableView是使用最多,也是最重要的一个控件,如果你不会用它,那别说什么大神了,菜鸟都不如. 其实关于UItableView事非常简单的,实 ...

  4. 高级UI晋升之自定义View实战(六)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从Android 自定义属性动画&Camera动画来介绍自定义V ...

  5. 高级UI晋升之自定义View实战(五)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从自定义View利器Canvas和Paint来进行详解 一.Canvas ...

  6. 高级UI晋升之布局ViewGroup(四)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从LinearLayout.RelativeLayout.FrameLa ...

  7. 高级UI晋升之常用View(三)中篇

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从ViewPager来介绍常用View:文章目录 一.简介 二.基本使用 ...

  8. 高级UI晋升之View渲染机制(二)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 优化性能一般从渲染,运算与内存,电量三个方面进行,今天开始说聊一聊Android ...

  9. 高级UI晋升之触摸事件分发机制(一)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 0. 前言 鉴于安卓分发机制较为复杂,故分为多个层次进行讲解,分别为基础篇.实践 ...

  10. Android 高级UI设计笔记21:Android SegmentView(分段选择控件)

    1. 分段控制(SegmentView) 首先我们先看看什么是SegmentView的效果,如下: 分段控制这个View控件是ios7的分段控制,和QQ消息页面顶部的效果一样,android没有这个控 ...

随机推荐

  1. 《BUG创造队》第九次团队作业:Beta冲刺与验收准备

    项目 内容 这个作业属于哪个课程 2016级软件工程 这个作业的要求在哪里 实验十三 团队作业9:Beta冲刺与团队项目验收 团队名称 BUG创造队 作业学习目标 (1)掌握软件黑盒测试技术:(2)学 ...

  2. kvm创建windows2008虚拟机

    virt-install -n win2008-fushi001 -r 16384 --vcpus=4 --os-type=windows --accelerate -c /data/kvm/imag ...

  3. Convert.ToString(null) => null

    { string str0 = Convert.ToString(null); Console.WriteLine("0,{0}", str0); if (str0==" ...

  4. Java 15周作业

    题目1:编写一个应用程序,输入用户名和密码,访问test数据库中t_login表(字段包括id.username.password),验证登录是否成功. 题目2:在上一题基础上,当登录成功后,将t_u ...

  5. BBS总结 --- django设计

    目录 1.调用模块使用 2.BBS中urls.py 3.django中配置 4.新学方法使用 5.BBS用到的知识点 1.调用模块使用 from django.db import models fro ...

  6. 使用vue-cli3搭建项目过程

    一.搭建前准备 node.js版本为8.9+: 安装模块:npm install -g n // 安装模块 这个模块是专门用来管理node.js版本的: 若原先已经安装,则更细模块:n stable ...

  7. windows下dos窗口实现持续ping显示时间保存至日志

    效果图 右击新建 ping.bat 文件(ping为文件名称,随便起),内容如下: cscript ping.vbs  127.0.0.1 -t >log.txt 127.0.0.1 修改为你自 ...

  8. 基于思岚A1激光雷达+OpenGL+VS2017的Ramer-Douglas-Peucker算法的实现

    时隔两年 又借到了之前的那个激光雷达,最老版本的思岚A1,甚至不支持新的固件,并且转接板也不见了,看了下淘宝店卖¥80,但是官方提供了一个基于STM32的实现方式,于是我估摸着这个转接板只是一个普通的 ...

  9. echo如何输出带颜色的文本

    本文链接:https://blog.csdn.net/qualcent/article/details/7106483 ######################################## ...

  10. Gift to XBACK(小小礼物)

    什么白天 什么黑夜 我没有 准备着给你的 Surprise 你给我的爱 让我觉得已足够 是你让我相信爱会有 是你的爱陪我绕宇宙 打开日记本写下忧愁 你却让我看时间轴 我才知道现在我能看到的画面 拥有你 ...