Android自定义ViewGroup实现竖向引导界面
程序员文章站
2022-11-14 10:59:01
一般进入app都有欢迎界面,基本都是水平滚动的,今天和大家分享一个垂直滚动的例子。
先来看看效果把:
1、首先是布局文件:
一般进入app都有欢迎界面,基本都是水平滚动的,今天和大家分享一个垂直滚动的例子。
先来看看效果把:
1、首先是布局文件:
<com.example.verticallinearlayout.verticallinearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/id_main_ly" android:layout_width="match_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#fff" > <relativelayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w02" > <button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hello" /> </relativelayout> <relativelayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w03" > <button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:background="#fff" android:text="hello" /> </relativelayout> <relativelayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w04" > <button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:text="hello" /> </relativelayout> <relativelayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w05" > <button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:text="hello" /> </relativelayout> </com.example.verticallinearlayout.verticallinearlayout>
在自定义的viewgroup中放入了4个relativelayout,每个relativelayout都设置了背景图片,背景图片来自微信~
2、主要看自定义的layout了
package com.example.verticallinearlayout; import android.content.context; import android.util.attributeset; import android.util.displaymetrics; import android.util.log; import android.view.motionevent; import android.view.velocitytracker; import android.view.view; import android.view.viewgroup; import android.view.windowmanager; import android.widget.scroller; public class verticallinearlayout extends viewgroup { /** * 屏幕的高度 */ private int mscreenheight; /** * 手指按下时的getscrolly */ private int mscrollstart; /** * 手指抬起时的getscrolly */ private int mscrollend; /** * 记录移动时的y */ private int mlasty; /** * 滚动的辅助类 */ private scroller mscroller; /** * 是否正在滚动 */ private boolean isscrolling; /** * 加速度检测 */ private velocitytracker mvelocitytracker; /** * 记录当前页 */ private int currentpage = 0; private onpagechangelistener monpagechangelistener; public verticallinearlayout(context context, attributeset attrs) { super(context, attrs); /** * 获得屏幕的高度 */ windowmanager wm = (windowmanager) context.getsystemservice(context.window_service); displaymetrics outmetrics = new displaymetrics(); wm.getdefaultdisplay().getmetrics(outmetrics); mscreenheight = outmetrics.heightpixels; // 初始化 mscroller = new scroller(context); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int count = getchildcount(); for (int i = 0; i < count; ++i) { view childview = getchildat(i); measurechild(childview, widthmeasurespec,mscreenheight); } } @override protected void onlayout(boolean changed, int l, int t, int r, int b) { if (changed) { int childcount = getchildcount(); // 设置主布局的高度 marginlayoutparams lp = (marginlayoutparams) getlayoutparams(); lp.height = mscreenheight * childcount; setlayoutparams(lp); for (int i = 0; i < childcount; i++) { view child = getchildat(i); if (child.getvisibility() != view.gone) { child.layout(l, i * mscreenheight, r, (i + 1) * mscreenheight);// 调用每个自布局的layout } } } } @override public boolean ontouchevent(motionevent event) { // 如果当前正在滚动,调用父类的ontouchevent if (isscrolling) return super.ontouchevent(event); int action = event.getaction(); int y = (int) event.gety(); obtainvelocity(event); switch (action) { case motionevent.action_down: mscrollstart = getscrolly(); mlasty = y; break; case motionevent.action_move: if (!mscroller.isfinished()) { mscroller.abortanimation(); } int dy = mlasty - y; // 边界值检查 int scrolly = getscrolly(); // 已经到达顶端,下拉多少,就往上滚动多少 if (dy < 0 && scrolly + dy < 0) { dy = -scrolly; } // 已经到达底部,上拉多少,就往下滚动多少 if (dy > 0 && scrolly + dy > getheight() - mscreenheight) { dy = getheight() - mscreenheight - scrolly; } scrollby(0, dy); mlasty = y; break; case motionevent.action_up: mscrollend = getscrolly(); int dscrolly = mscrollend - mscrollstart; if (wantscrolltonext())// 往上滑动 { if (shouldscrolltonext()) { mscroller.startscroll(0, getscrolly(), 0, mscreenheight - dscrolly); } else { mscroller.startscroll(0, getscrolly(), 0, -dscrolly); } } if (wantscrolltopre())// 往下滑动 { if (shouldscrolltopre()) { mscroller.startscroll(0, getscrolly(), 0, -mscreenheight - dscrolly); } else { mscroller.startscroll(0, getscrolly(), 0, -dscrolly); } } isscrolling = true; postinvalidate(); recyclevelocity(); break; } return true; } /** * 根据滚动距离判断是否能够滚动到下一页 * * @return */ private boolean shouldscrolltonext() { return mscrollend - mscrollstart > mscreenheight / 2 || math.abs(getvelocity()) > 600; } /** * 根据用户滑动,判断用户的意图是否是滚动到下一页 * * @return */ private boolean wantscrolltonext() { return mscrollend > mscrollstart; } /** * 根据滚动距离判断是否能够滚动到上一页 * * @return */ private boolean shouldscrolltopre() { return -mscrollend + mscrollstart > mscreenheight / 2 || math.abs(getvelocity()) > 600; } /** * 根据用户滑动,判断用户的意图是否是滚动到上一页 * * @return */ private boolean wantscrolltopre() { return mscrollend < mscrollstart; } @override public void computescroll() { super.computescroll(); if (mscroller.computescrolloffset()) { scrollto(0, mscroller.getcurry()); postinvalidate(); } else { int position = getscrolly() / mscreenheight; log.e("xxx", position + "," + currentpage); if (position != currentpage) { if (monpagechangelistener != null) { currentpage = position; monpagechangelistener.onpagechange(currentpage); } } isscrolling = false; } } /** * 获取y方向的加速度 * * @return */ private int getvelocity() { mvelocitytracker.computecurrentvelocity(1000); return (int) mvelocitytracker.getyvelocity(); } /** * 释放资源 */ private void recyclevelocity() { if (mvelocitytracker != null) { mvelocitytracker.recycle(); mvelocitytracker = null; } } /** * 初始化加速度检测器 * * @param event */ private void obtainvelocity(motionevent event) { if (mvelocitytracker == null) { mvelocitytracker = velocitytracker.obtain(); } mvelocitytracker.addmovement(event); } /** * 设置回调接口 * * @param onpagechangelistener */ public void setonpagechangelistener(onpagechangelistener onpagechangelistener) { monpagechangelistener = onpagechangelistener; } /** * 回调接口 * * @author zhy * */ public interface onpagechangelistener { void onpagechange(int currentpage); } }
注释还是相当详细的,我简单描述一下,action_down时获得当前的scrolly,然后action_move时,根据移动的距离不断scrollby就行了,当前处理了一下边界判断,在action_up中再次获得scrolly,两个的scrolly进行对比,然后根据移动的距离与方向决定最后的动作。
3、主activity
package com.example.verticallinearlayout; import android.app.activity; import android.os.bundle; import android.widget.toast; import com.example.verticallinearlayout.verticallinearlayout.onpagechangelistener; public class mainactivity extends activity { private verticallinearlayout mmianlayout; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mmianlayout = (verticallinearlayout) findviewbyid(r.id.id_main_ly); mmianlayout.setonpagechangelistener(new onpagechangelistener() { @override public void onpagechange(int currentpage) { // mmianlayout.getchildat(currentpage); toast.maketext(mainactivity.this, "第"+(currentpage+1)+"页", toast.length_short).show(); } }); } }
为了提供可扩展性,还是定义了回调接口,完全可以把这个当成一个垂直的viewpager使用。
总结下:
scroller这个辅助类还是相当好用的,原理我简单说一下:每次滚动时,让scroller进行滚动,然后调用postinvalidate方法,这个方法会引发调用ondraw方法,ondraw方法中会去调用computescroll方法,然后我们在computscroll中判断,scroller的滚动是否结束,没有的话,把当前的view滚动到现在scroller的位置,然后继续调用postinvalidate,这样一个循环的过程。
画张图方便大家理解,ps:没找到什么好的画图工具,那rose随便画了,莫计较。
源码下载:android自定义viewgroup实现竖向引导界面
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 当年和先生在一起时
推荐阅读
-
Android自定义View实现微信语音界面
-
Android自定义ViewGroup实现淘宝商品详情页
-
Android自定义ViewGroup实现竖向引导界面
-
Android 自定义ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能)
-
Android自定义ViewGroup实现朋友圈九宫格控件
-
Android自定义ViewGroup的实现
-
Android自定义控件----继承ViewGroup自定义ViewPager2,使用Scroller实现平滑移动
-
Android自定义ViewGroup实现淘宝商品详情页
-
Android自定义ViewGroup实现竖向引导界面
-
Android自定义ViewGroup实现标签浮动效果