自定义控件在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. python iter()函数迭代器

    迭代器为类序列对象提供了一个类序列的接口.python的迭代无缝地支持序列对象,而且它还允许程序员迭代非序列类型,包括用户定义的对象.迭代器用起来很灵巧,你可以迭代不是序列但表现处序列行为的对象,例如 ...

  2. 持续集成学习10 Pipline初探

    一.流水线概述 1.案例 2.流水线语法(input 处会阻塞住让你选择) 3.执行脚本 4.查看语法

  3. 从.NET/CLR返回的hresult:0x8013XXXX的解释

    什么是0x8013XXXX 有时您可能会遇到从.NET返回的神秘HRESULT,它以0x8013开头,例如0x80131522.不幸的是,Visual Studio附带的错误查找并不能真正处理那些奇怪 ...

  4. jsDOM分享1

    java scrip-DOM概念分享 在java script中有三大核心分别为:javascript语法,DOM,BOM. 今天分享一下在学习dom后的一些理解,希望大家支持. 绑定事件 之前学习过 ...

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

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

  6. .NET Core入门程序及命令行练习

    用命令行一步一步新建项目.添加Package.Restore.Build.Run 执行的实现方式,更让容易让我们了解.NET Core的运行机制. 准备工作 安装.NET Core 运行环境,下载地址 ...

  7. 81: luogu3370 hash

    hash 模板题 #include <bits/stdc++.h> using namespace std; #define ULL unsigned long long const UL ...

  8. Linux修改服务器Oracle字符集

    Linux安装Oracle时太仓促,没设置好,导入dmp字符集(ZHS16GBK)与服务器字符集(WE8MSWIN1252)对不上,导致导入数据失败: [oracle@ORACLE ~]$ sqlpl ...

  9. 【洛谷P5596】【XR-4】题

    solution \(y^2-x^2=ax+b\) \(y^2=x^2+ax+b\) 当\(x^2+ax+b\)为完全平方式时\(Ans=inf\) \(x \leq y\) 不妨令 \(y=x+t\ ...

  10. 洛谷P1043数字游戏

    题目 区间DP,将\(maxn[i][j][k]\)表示为i到j区间内分为k个区间所得到的最大值,\(minn\)表示最小值. 然后可以得到状态转移方程: \[maxn[i][j][k]= max(m ...