为View设置左右切换动画
程序员文章站
2023-04-07 23:10:00
本文同步自http://javaexception.com/archives/64 问题: 近期的需求中,碰到了一个view切换动画的需求。要实现的是点击按钮,从左到右滑动view,左边的view消失,右边的view出现。有点像文字跑马灯的效果,不过这次滚动的是view,具体看截图效果。 实现思路: ......
本文同步自
问题:
近期的需求中,碰到了一个view切换动画的需求。要实现的是点击按钮,从左到右滑动view,左边的view消失,右边的view出现。有点像文字跑马灯的效果,不过这次滚动的是view,具体看截图效果。
实现思路:
晚上在家写了一个比较low的实现方案,参考的思路是banner轮播的思路,用viewpager来进行view的切换。大致效果也还行,只不过觉得代码量太多,使用比较麻烦。我就是想给两个view加上可以切换动画的效果,就要写那么多的代码,感觉不划算。只好放弃此方案。
随后想到了swipeview,发现这是一个挺好的点,可以从这里入手。经过对swipemenulayout代码的阅读分析以及测试实践。得出了以下的解决方案。
自定义slidelayout.java
public class slidelayout extends viewgroup { private static final string tag = "slidelayout"; private int mheight; private view mcontentview; private view mrightview; private boolean isanimation = false; public slidelayout(context context) { this(context, null); } public slidelayout(context context, attributeset attrs) { this(context, attrs, 0); } public slidelayout(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { //log.d(tag, "onmeasure() called with: " + "widthmeasurespec = [" + widthmeasurespec + "], heightmeasurespec = [" + heightmeasurespec + "]"); super.onmeasure(widthmeasurespec, heightmeasurespec); mheight = 0; int contentwidth = 0; int childcount = getchildcount(); final boolean measurematchparentchildren = measurespec.getmode(heightmeasurespec) != measurespec.exactly; boolean isneedmeasurechildheight = false; for (int i = 0; i < childcount; i++) { view childview = getchildat(i); if (childview.getvisibility() != gone) { measurechild(childview, widthmeasurespec, heightmeasurespec); final marginlayoutparams lp = (marginlayoutparams) childview.getlayoutparams(); mheight = math.max(mheight, childview.getmeasuredheight()/* + lp.topmargin + lp.bottommargin*/); if (measurematchparentchildren && lp.height == layoutparams.match_parent) { isneedmeasurechildheight = true; } if (i == 0) { mcontentview = childview; contentwidth = childview.getmeasuredwidth(); } else { mrightview = childview; } } } setmeasureddimension(getpaddingleft() + getpaddingright() + contentwidth, mheight + getpaddingtop() + getpaddingbottom());//宽度取第一个item(content)的宽度 if (isneedmeasurechildheight) {//如果子view的height有matchparent属性的,设置子view高度 forceuniformheight(childcount, widthmeasurespec); } } @override public layoutparams generatelayoutparams(attributeset attrs) { return new marginlayoutparams(getcontext(), attrs); } /** * 给matchparent的子view设置高度 * * @param count * @param widthmeasurespec * @see android.widget.linearlayout# 同名方法 */ private void forceuniformheight(int count, int widthmeasurespec) { // pretend that the linear layout has an exact size. this is the measured height of // ourselves. the measured height should be the max height of the children, changed // to accommodate the heightmeasurespec from the parent int uniformmeasurespec = measurespec.makemeasurespec(getmeasuredheight(), measurespec.exactly);//以父布局高度构建一个exactly的测量参数 for (int i = 0; i < count; ++i) { final view child = getchildat(i); if (child.getvisibility() != gone) { marginlayoutparams lp = (marginlayoutparams) child.getlayoutparams(); if (lp.height == layoutparams.match_parent) { // temporarily force children to reuse their old measured width int oldwidth = lp.width;//measurechildwithmargins 这个函数会用到宽,所以要保存一下 lp.width = child.getmeasuredwidth(); // remeasure with new dimensions measurechildwithmargins(child, widthmeasurespec, 0, uniformmeasurespec, 0); lp.width = oldwidth; } } } } @override protected void onlayout(boolean changed, int l, int t, int r, int b) { //log.e(tag, "onlayout() called with: " + "changed = [" + changed + "], l = [" + l + "], t = [" + t + "], r = [" + r + "], b = [" + b + "]"); int childcount = getchildcount(); int left = 0 + getpaddingleft(); for (int i = 0; i < childcount; i++) { view childview = getchildat(i); if (childview.getvisibility() != gone) { if (i == 0) {//第一个子view是内容 宽度设置为全屏 childview.layout(left, getpaddingtop(), left + childview.getmeasuredwidth(), getpaddingtop() + childview.getmeasuredheight()); left = left + childview.getmeasuredwidth(); } else { childview.layout(left, getpaddingtop(), left + childview.getmeasuredwidth(), getpaddingtop() + childview.getmeasuredheight()); left = left + childview.getmeasuredwidth(); } } } //log.d(tag, "onlayout() called with: " + "maxscrollgap = [" + maxscrollgap + "], l = [" + l + "], t = [" + t + "], r = [" + r + "], b = [" + b + "]"); } public void slideleft(long duration) { if (isanimation) { return; } animatorset animatorset = new animatorset(); final objectanimator objectanimator1 = objectanimator.offloat(mcontentview, "translationx", 0, -mcontentview.getmeasuredwidth()); final objectanimator objectanimator2 = objectanimator.offloat(mrightview, "translationx", 0, -mcontentview.getmeasuredwidth()); animatorset.playtogether(objectanimator1, objectanimator2); animatorset.addlistener(new animatorlisteneradapter() { @override public void onanimationstart(animator animation) { super.onanimationstart(animation); isanimation = true; } @override public void onanimationend(animator animation) { super.onanimationend(animation); isanimation = false; } }); animatorset.setduration(duration); animatorset.start(); } public void slideright(long duration) { if (isanimation) { return; } animatorset animatorset = new animatorset(); final objectanimator objectanimator1 = objectanimator.offloat(mcontentview, "translationx", -mcontentview.getmeasuredwidth(), 0); final objectanimator objectanimator2 = objectanimator.offloat(mrightview, "translationx", -mcontentview.getmeasuredwidth(), 0); animatorset.playtogether(objectanimator1, objectanimator2); animatorset.addlistener(new animatorlisteneradapter() { @override public void onanimationstart(animator animation) { super.onanimationstart(animation); isanimation = true; } @override public void onanimationend(animator animation) { super.onanimationend(animation); isanimation = false; } }); animatorset.setduration(duration); animatorset.start(); } }
接着看看如何使用,调用方式。
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".mainactivity"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="向左滑动" /> <button android:id="@+id/btn_start2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="向右滑动" /> </linearlayout> <me.star.animator.slidelayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margintop="10dp" android:orientation="horizontal"> <textview android:id="@+id/btn_show" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/coloraccent" android:padding="4dp" android:text="展示1" android:textsize="20sp" android:visibility="visible" /> <textview android:id="@+id/btn_show2" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_green_light" android:padding="4dp" android:text="展示2" android:textsize="20sp" /> </me.star.animator.slidelayout> </linearlayout>
@override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); btnshow = findviewbyid(r.id.btn_show); btnshow2 = findviewbyid(r.id.btn_show2); btnstart = findviewbyid(r.id.btn_start); btnstart2 = findviewbyid(r.id.btn_start2); container = findviewbyid(r.id.container); btnstart.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { container.slideleft(3000); } }); btnstart2.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { container.slideright(3000); } }); }
其他相关:
看到泡网上有一个为view和activity设置左右切换动画的文章
代码下载:
链接:https://pan.baidu.com/s/1tg7-ejysozqegu-fqy4how 密码:c8q8
上一篇: 利用Dectorator分模块存储Vuex状态的实现
下一篇: 微信小程序实现的自定义分享功能示例