自定义控件在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. WinForm 捕获异常 Application.ThreadException + AppDomain.CurrentDomain.UnhandledException

     WinForm 捕获未处理的异常,可以使用Application.ThreadException 和AppDomain.CurrentDomain.UnhandledException事件 WinF ...

  2. .Net Core控制台生成exe能独立运行

    .Net Core控制台生成exe能独立运行,依赖文件都单独生成在一个publish文件夹里 方式一:强烈推荐,能独立运行,依赖DLL也会生成出来,支持无安装环境也能到处运行 按win+R输入cmd在 ...

  3. [POJ2083] Fracal

    Description A fractal is an object or quantity that displays self-similarity, in a somewhat technica ...

  4. springboot 整合Swagger2的使用

    Swagger2相较于传统Api文档的优点 手写Api文档的几个痛点: 文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时. 接口返回结果不明确 不能直接在线测试接口,通常需要使用工 ...

  5. 最小圆覆盖(洛谷 P1742 增量法)

    题意:给定N个点,求最小圆覆盖的圆心喝半径.保留10位小数点. N<1e5: 思路:因为精度要求较高,而且N比较大,所以三分套三分的复杂度耶比较高,而且容易出错. 然是写下增量法吧. 伪代码加深 ...

  6. JDK1.8 java.io.Serializable接口详解

    java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法.只是用于标识此接口的实现类可以被序列化与反序列化.但是它的奥秘并非像它表现的这样简单.现在从以下几个问题 ...

  7. cookie插件|jq-cookie.js|使用详解

    1.设置一二级域名共用的cookie:设置domain为一级域名,可一.二级域名共用的cookie $.cookie('f_city','北京|101010100|,锦州|101070701|',{e ...

  8. 学习:c++指向指针的指针(多级间接寻址)

    指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链.通常,一个指针包含一个变量的地址.当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置. 当一个 ...

  9. 从TEB到PEB再到SEH(二)

    什么是SEH? SEH( Structured Exception Handling , 结构化异常处理 ) 结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能.而Visual C ...

  10. 获取页面scroll高度

    记录一下获取 scroll 高度的方法 经实际测试: document.body.scrollTop 在 chrome 下会返回0. 所以 document.documentElement.scrol ...