Android实现3D层叠式卡片图片展示
程序员文章站
2023-11-14 16:58:58
本文实例为大家分享了android实现3d层叠式卡片图片展示的具体代码,供大家参考,具体内容如下
先看效果
好了效果看了,感兴趣的往下看哦!
整体实现思路
1、重写rela...
本文实例为大家分享了android实现3d层叠式卡片图片展示的具体代码,供大家参考,具体内容如下
先看效果
好了效果看了,感兴趣的往下看哦!
整体实现思路
1、重写relativelayout 实现 锁定宽高比例的 relativelayout
2、自定义一个支持滑动的面板 继承 viewgroup
3、卡片view绘制
4、页面中使用布局
首先为了更好的展示图片我们重写一下 relativelayout 编写一个锁定宽高比例的 relativelayout
autoscalerelativelayout
public class autoscalerelativelayout extends relativelayout { //宽高比例 private float widthheightrate = 0.35f; public autoscalerelativelayout(context context) { this(context, null); } public autoscalerelativelayout(context context, attributeset attrs) { this(context, attrs, 0); } public autoscalerelativelayout(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); //通过布局获取宽高比例 typedarray a = context.obtainstyledattributes(attrs, r.styleable.card, 0, 0); widthheightrate = a.getfloat(r.styleable.card_widthheightrate, widthheightrate); a.recycle(); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); // 调整高度 int width = getmeasuredwidth(); int height = (int) (width * widthheightrate); viewgroup.layoutparams lp = getlayoutparams(); lp.height = height; setlayoutparams(lp); } }
这样我们就编写好了我们想要的父布局
使用方法
<com.petterp.toos.imagecard.autoscalerelativelayout android:id="@+id/card_top_layout" android:layout_width="match_parent" android:layout_height="wrap_content" card:widthheightrate="0.6588"> <!-- widthheightrate:就是设置宽高的百分比--> <imageview android:id="@+id/card_image_view" android:layout_width="fill_parent" android:layout_height="match_parent" android:scaletype="fitxy" /> <!-- 这是我们展示的图片--> <view android:id="@+id/maskview" android:layout_width="fill_parent" android:layout_height="match_parent" android:background="?android:attr/selectableitembackground" android:clickable="true" /> <!-- 这个是为了让我们图片上有波纹--> </com.petterp.toos.imagecard.autoscalerelativelayout>
接下来就是主要布局,也就是展示图片的布局了
为了实现滑动我们编写一个支持滑动的画板
//事件处理 @override public boolean dispatchtouchevent(motionevent ev) { int action = ev.getactionmasked(); // 按下时保存坐标信息 if (action == motionevent.action_down) { this.downpoint.x = (int) ev.getx(); this.downpoint.y = (int) ev.gety(); } return super.dispatchtouchevent(ev); } /* touch事件的拦截与处理都交给mdraghelper来处理 */ @override public boolean onintercepttouchevent(motionevent ev) { boolean shouldintercept = mdraghelper.shouldintercepttouchevent(ev); boolean moveflag = movedetector.ontouchevent(ev); int action = ev.getactionmasked(); if (action == motionevent.action_down) { // action_down的时候就对view重新排序 if (mdraghelper.getviewdragstate() == viewdraghelper.state_settling) { mdraghelper.abort(); } orderviewstack(); // 保存初次按下时arrowflagview的y坐标 // action_down时就让mdraghelper开始工作,否则有时候导致异常 mdraghelper.processtouchevent(ev); } return shouldintercept && moveflag; } @override public boolean ontouchevent(motionevent e) { try { // 统一交给mdraghelper处理,由draghelpercallback实现拖动效果 // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch mdraghelper.processtouchevent(e); } catch (exception ex) { ex.printstacktrace(); } return true; } //计算 @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { measurechildren(widthmeasurespec, heightmeasurespec); int maxwidth = measurespec.getsize(widthmeasurespec); int maxheight = measurespec.getsize(heightmeasurespec); setmeasureddimension( resolvesizeandstate(maxwidth, widthmeasurespec, 0), resolvesizeandstate(maxheight, heightmeasurespec, 0)); allwidth = getmeasuredwidth(); allheight = getmeasuredheight(); } //定位 @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { // 布局卡片view int size = viewlist.size(); for (int i = 0; i < size; i++) { view viewitem = viewlist.get(i); int childheight = viewitem.getmeasuredheight(); int viewleft = (getwidth() - viewitem.getmeasuredwidth()) / 2; viewitem.layout(viewleft, itemmargintop, viewleft + viewitem.getmeasuredwidth(), itemmargintop + childheight); int offset = yoffsetstep * i; float scale = 1 - scale_step * i; if (i > 2) { // 备用的view offset = yoffsetstep * 2; scale = 1 - scale_step * 2; } viewitem.offsettopandbottom(offset); viewitem.setscalex(scale); viewitem.setscaley(scale); } // 布局底部按钮的view if (null != bottomlayout) { int layouttop = viewlist.get(0).getbottom() + bottommargintop; bottomlayout.layout(left, layouttop, right, layouttop + bottomlayout.getmeasuredheight()); } // 初始化一些中间参数 initcenterviewx = viewlist.get(0).getleft(); initcenterviewy = viewlist.get(0).gettop(); childwith = viewlist.get(0).getmeasuredwidth(); } //onfinishinflate 当view中所有的子控件均被映射成xml后触发 @override protected void onfinishinflate() { super.onfinishinflate(); // 渲染完成,初始化卡片view列表 viewlist.clear(); int num = getchildcount(); for (int i = num - 1; i >= 0; i--) { view childview = getchildat(i); if (childview.getid() == r.id.card_bottom_layout) { bottomlayout = childview; initbottomlayout(); } else { // for循环取view的时候,是从外层往里取 carditemview viewitem = (carditemview) childview; viewitem.setparentview(this); viewitem.settag(i + 1); viewitem.maskview.setonclicklistener(btnlistener); viewlist.add(viewitem); } } carditemview bottomcardview = viewlist.get(viewlist.size() - 1); bottomcardview.setalpha(0); }
卡片view绘制
private void initspring() { springconfig springconfig = springconfig.frombouncinessandspeed(15, 20); springsystem mspringsystem = springsystem.create(); springx = mspringsystem.createspring().setspringconfig(springconfig); springy = mspringsystem.createspring().setspringconfig(springconfig); springx.addlistener(new simplespringlistener() { @override public void onspringupdate(spring spring) { int xpos = (int) spring.getcurrentvalue(); setscreenx(xpos); parentview.onviewposchanged(carditemview.this); } }); springy.addlistener(new simplespringlistener() { @override public void onspringupdate(spring spring) { int ypos = (int) spring.getcurrentvalue(); setscreeny(ypos); parentview.onviewposchanged(carditemview.this); } }); } //装载数据 public void filldata(carddataitem itemdata) { glide.with(getcontext()).load(itemdata.imagepath).into(imageview); } /** * 动画移动到某个位置 */ public void animto(int xpos, int ypos) { setcurrentspringpos(getleft(), gettop()); springx.setendvalue(xpos); springy.setendvalue(ypos); } /** * 设置当前spring位置 */ private void setcurrentspringpos(int xpos, int ypos) { springx.setcurrentvalue(xpos); springy.setcurrentvalue(ypos); }
接下来我们需要使用它 编写fragment布局
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:card="http://schemas.android.com/apk/res-auto" android:background="#fff" android:orientation="vertical"> <com.petterp.toos.imagecard.cardslidepanel android:id="@+id/image_slide_panel" android:layout_width="match_parent" android:layout_height="match_parent" card:bottommargintop="38dp" card:itemmargintop="10dp" card:yoffsetstep="26dp"> <linearlayout android:id="@+id/card_bottom_layout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <button android:background="#03a9f4" android:text="右侧移除" android:id="@+id/card_left_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <button android:background="#03a9f4" android:text="右侧移除" android:id="@+id/card_right_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="10dp" /> </linearlayout> <com.petterp.toos.imagecard.carditemview android:layout_width="match_parent" android:layout_height="wrap_content" /> <com.petterp.toos.imagecard.carditemview android:layout_width="match_parent" android:layout_height="wrap_content" /> <com.petterp.toos.imagecard.carditemview android:layout_width="match_parent" android:layout_height="wrap_content" /> <com.petterp.toos.imagecard.carditemview android:layout_width="match_parent" android:layout_height="wrap_content" /> </com.petterp.toos.imagecard.cardslidepanel> </linearlayout>
代码中的使用
private void initview(view rootview) { cardslidepanel slidepanel = (cardslidepanel) rootview .findviewbyid(r.id.image_slide_panel); cardswitchlistener = new cardslidepanel.cardswitchlistener() { @override public void onshow(int index) { toast.maketext(getcontext(), "cardfragment"+"正在显示=" +index, toast.length_short).show(); } //type 0=右边 ,-1=左边 @override public void oncardvanish(int index, int type) { toast.maketext(getcontext(), "cardfragment"+ "正在消失=" + index + " 消失type=" + type, toast.length_short).show(); } @override public void onitemclick(view cardview, int index) { toast.maketext(getcontext(), "cardfragment"+"卡片点击=" + index, toast.length_short).show(); } }; slidepanel.setcardswitchlistener(cardswitchlistener); preparedatalist(); slidepanel.filldata(datalist); } //封装数据 private void preparedatalist() { int num = imagepaths.length; //重复添加数据10次(测试数据太少) for (int j = 0; j < 10; j++) { for (int i = 0; i < num; i++) { carddataitem dataitem = new carddataitem(); dataitem.imagepath = imagepaths[i]; datalist.add(dataitem); } } }
到此主要逻辑代码就编写完了
详细说明代码中已经注释 ,全部代码请看源码
源码:github源码
源码中的testcardfragment 为使用模板
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java微服务:dubbo-admin控制台是使用
下一篇: 1.基础语法