Android 仿土巴兔选择效果
1,前两天在群里看到有人在讨论土巴兔的选择装修风格的效果,自己也想实现,果断百度一下,有些好的文章,就花了些时间来分析了下,先看看别人土巴兔原装的功能
2,可以看到,基本上可以使用一个vviewpager来实现,主要技术点一下
①android:clipChildren设置为false,意味着不限制子View在其范围内,也就是说子view可以超出父view的范围
②通过PageTransformer来实现缩放动画
③拦截点击事件的位置来实现点击切换viewpager
来看一下代码,首先看一下布局文件main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?xml version= "1.0" encoding= "utf-8" ?> <RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:app= "http://schemas.android.com/apk/res-auto" xmlns:tools= "http://schemas.android.com/tools" android:id= "@+id/page_container" android:layout_width= "match_parent" android:layout_height= "match_parent" android:background= "@android:color/white" android:clipChildren= "false" app:layout_behavior= "@string/appbar_scrolling_view_behavior" tools:context= ".MainActivity" tools:showIn= "@layout/activity_main" > <com.wangjitao.tubatudemo.view.ClipViewPager android:id= "@+id/viewPager" android:layout_width= "200dp" android:layout_height= "200dp" android:layout_centerInParent= "true" android:clipChildren= "false" android:overScrollMode= "never" /> </RelativeLayout> |
其中ClipViewPager是一个自定义的viewpager,主要实现了两个功能,一,判断用户点击事件在不在Viewpager中,二,若在,则设置当前页为其
ClipViewPager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package com.wangjitao.tubatudemo.view; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * Created by wangjitao on 2016/4/15. */ public class ClipViewPager extends ViewPager{ public ClipViewPager(Context context) { super (context); } public ClipViewPager(Context context, AttributeSet attrs) { super (context, attrs); } /** * 重写点击事件,当用户抬起的时候 判断用户点击的区域是否在viewPager的区域中 * 如果是,在判断是在哪个子view上,然后设置当前页为该view * @param ev * @return */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_UP){ View view = viewOfClickOnScreen(ev); if (view != null ){ setCurrentItem(indexOfChild(view)); } } return super .dispatchTouchEvent(ev); } private View viewOfClickOnScreen(MotionEvent ev) { int childCount = getChildCount(); int [] location = new int [ 2 ]; for ( int i = 0 ; i < childCount; i++) { View v = getChildAt(i); v.getLocationOnScreen(location); int minX = location[ 0 ]; int minY = getTop(); int maxX = location[ 0 ] + v.getWidth(); int maxY = getBottom(); float x = ev.getX(); float y = ev.getY(); if ((x > minX && x < maxX) && (y > minY && y < maxY)) { return v; } } return null ; } } |
三,编写自定义的PageTransformer ,来实现当前页切换下一页的控件的缩放问题
ScalePageTransformer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.wangjitao.tubatudemo.view; import android.os.Build; import android.support.v4.view.ViewPager; import android.view.View; /** * Created by wangjitao on 2016/4/15. */ public class ScalePageTransformer implements ViewPager.PageTransformer { public static final float MAX_SCALE = 1 .2f ; public static final float MIN_SCALE = 0 .6f ; /** * 当处于最中间的view往左边滑动时,它的position值是小于0的,并且是越来越小,它右边的view的position是从1逐渐减小到0的。 * @param page * @param position */ @Override public void transformPage(View page, float position) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { page.getParent().requestLayout(); } if (position < - 1 ) { position = - 1 ; } else if (position > 1 ) { position = 1 ; } float tempScale = position < 0 ? 1 + position : 1 - position; float slope = (MAX_SCALE - MIN_SCALE) / 1 ; float scaleValue = MIN_SCALE + tempScale * slope; page.setScaleX(scaleValue); page.setScaleY(scaleValue); } } |
基本上就可以实现了,再贴一下是MainActivity.java和ViewPager的Adapter
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | package com.wangjitao.tubatudemo; import android.content.Context; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.MotionEvent; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.RelativeLayout; import com.wangjitao.tubatudemo.adapter.ClipPagerAdapter; import com.wangjitao.tubatudemo.view.ClipViewPager; import com.wangjitao.tubatudemo.view.ScalePageTransformer; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private Context mContext = MainActivity. this ; private ClipViewPager mViewPager ; private ClipPagerAdapter mClipViewPager ; private List<Integer> mData ; private RelativeLayout mRelativeLayout ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Hi Girl" , Snackbar.LENGTH_LONG) .setAction( "Action" , null ).show(); } }); initView(); initData(); } private void initView() { mViewPager = (ClipViewPager) findViewById(R.id.viewPager) ; mViewPager.setPageTransformer( true , new ScalePageTransformer()); mRelativeLayout = (RelativeLayout) findViewById(R.id.page_container); //需要将整个页面的事件分发给ViewPager,不然的话只有ViewPager中间的view能滑动,其他的都不能滑动,这是肯定的, //因为ViewPager总体布局就是中间那一块大小,其他的子布局都跑到ViewPager外面来了 mRelativeLayout.setOnTouchListener( new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mViewPager.dispatchTouchEvent(event); } }); mData = new ArrayList<>(); mClipViewPager = new ClipPagerAdapter(mData,mContext); mViewPager.setAdapter(mClipViewPager); } private void initData() { mData.add(R.mipmap.style_xiandai); mData.add(R.mipmap.style_jianyue); mData.add(R.mipmap.style_oushi); mData.add(R.mipmap.style_zhongshi); mData.add(R.mipmap.style_meishi); mData.add(R.mipmap.style_dzh); mData.add(R.mipmap.style_dny); mData.add(R.mipmap.style_rishi); mViewPager.setOffscreenPageLimit(mData.size()); mClipViewPager.notifyDataSetChanged(); } } |
ViewPager的适配器 ClipPagerAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.wangjitao.tubatudemo.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import java.util.List; /** * Created by jh on 2016/4/15. */ public class ClipPagerAdapter extends RecyclingPagerAdapter { private List<Integer> mData ; private Context mContext ; public ClipPagerAdapter(List<Integer> mData ,Context mContext ) { this .mData = mData ; this .mContext = mContext ; } @Override public View getView( int position, View convertView, ViewGroup container) { ImageView imageView = null ; if (convertView == null ){ imageView = new ImageView(mContext); } else { imageView = (ImageView) convertView ; } imageView.setTag(position); imageView.setImageResource(mData.get(position)); return imageView; } @Override public int getCount() { return mData.size(); } } |
ok ,基本上就完成了 ,看一看效果
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步