高级UI-自定义控件
自定义控件在Android开发中有着大量的运用,为了做出符合项目的效果很多时候需要自定义控件,这里就使用两个自定义控件,来说明自定义控件的使用流程
仿QQ侧滑
之前使用DrawerLayout
和NavigationView
都实现了侧滑的效果,在这里使用自定义的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-自定义控件的更多相关文章
- firefox 扩展开发笔记(三):高级ui交互编程
firefox 扩展开发笔记(三):高级ui交互编程 前言 前两篇链接 1:firefox 扩展开发笔记(一):jpm 使用实践以及调试 2:firefox 扩展开发笔记(二):进阶开发之移动设备模拟 ...
- Android 高级UI设计笔记07:RecyclerView 的详解
1. 使用RecyclerView 在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...
- iOS开发——高级UI&带你玩转UITableView
带你玩装UITableView 在实际iOS开发中UITableView是使用最多,也是最重要的一个控件,如果你不会用它,那别说什么大神了,菜鸟都不如. 其实关于UItableView事非常简单的,实 ...
- 高级UI晋升之自定义View实战(六)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从Android 自定义属性动画&Camera动画来介绍自定义V ...
- 高级UI晋升之自定义View实战(五)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从自定义View利器Canvas和Paint来进行详解 一.Canvas ...
- 高级UI晋升之布局ViewGroup(四)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从LinearLayout.RelativeLayout.FrameLa ...
- 高级UI晋升之常用View(三)中篇
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680本篇文章将从ViewPager来介绍常用View:文章目录 一.简介 二.基本使用 ...
- 高级UI晋升之View渲染机制(二)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 优化性能一般从渲染,运算与内存,电量三个方面进行,今天开始说聊一聊Android ...
- 高级UI晋升之触摸事件分发机制(一)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 0. 前言 鉴于安卓分发机制较为复杂,故分为多个层次进行讲解,分别为基础篇.实践 ...
- Android 高级UI设计笔记21:Android SegmentView(分段选择控件)
1. 分段控制(SegmentView) 首先我们先看看什么是SegmentView的效果,如下: 分段控制这个View控件是ios7的分段控制,和QQ消息页面顶部的效果一样,android没有这个控 ...
随机推荐
- class Pagination(object)分页源码
class Pagination(object): def init(self, current_page, all_count, per_page_num=10, pager_count=11): ...
- 神奇的 Object.defineProperty 解释说明
原文 : https://segmentfault.com/a/1190000004346467?utm_source=tuicool&utm_medium=referral 这个方法了不起啊 ...
- django-mysql事务
django文档:https://yiyibooks.cn/xx/django_182/topics/db/transactions.html mysql事务 1) 事务概念 一组mysql语句,要么 ...
- 13-Flutter移动电商实战-ADBanner组件的编写
1.AdBanner组件的编写 我们还是把这部分单独出来,需要说明的是,这个Class你也是可以完全独立成一个dart文件的.代码如下: 广告图片class AdBanner extends Stat ...
- java正则表达式——规则表
常用正则规则: 构造 匹配 字符 \\ 反斜线字符 \r 回车符 ('\u000D') \n 新行(换行)符 ('\u000A') 字符类 [abc] a.b 或 c [^abc] 任何字符,除了 a ...
- 洛谷 UVA12563 Jin Ge Jin Qu hao 题解
这道题其实是一道01背包的变形题,主要思路如下:在不把剩余时间用光的前提下(剩余时间>0),尽可能的多唱歌.于是我们可以用dp[i]表示的是到当前i秒时,最多可以唱多少歌. 状态转换方程:dp[ ...
- /etc/rc.local
/etc/rc.local是/etc/rc.d/rc.local的软连接 应用于指定开机启动的进程 开机启动不生效,则首先需要检查下/etc/rc.d/rc.local是否具有可执行权限 在配置文件中 ...
- nginx 添加用户认证
nginx 添加用户认证 nginx 配置文件添加: 配置代理添加用户认证:server { listen ; server_name localhost; location ...
- 初试angularjs动画(animate)
angularjs不同版本的代码写法各有千秋,动画模块的写法也各有不同,以下是收集到的两大版本的写法,各位请: angularjs1.1.5版本(1.2之前) index.html代码: <!D ...
- Linux+Tomcat环境下安装SSL证书
1.将申请好的证书(4个文件)文件放入/home/tomcat/apache-tomcat-9.0.12/conf/cert文件夹下2.(或者)将申请好的证书(4个文件)文件放入/home/tomca ...