Android 自定义viewpager 三张图片在同一屏幕轮播的效果

github:https://github.com/nickeyCode/RoundImageViewPager

说实话不知道怎么描述这个效果,在网页上见得跟多,公司要求做这个效果得时候不知道怎么用文字描述找不到对应的dome只好自己写。

先上图

大概效果就是这个。主要用的的知识点就是viewpager的自定义动画。

项目目录:

roundimg是圆形图片,继承ImageView的,上网好多可以搜索得到

viewpager主要分成三部分

一是viewpager本身,设置adapter,绑定监听器等。

二是adapter,继承PagerAdapter,用法跟listview的差不多。

三是动画类,继承PageTransformer。

首先看看最核心的动画类(能做到这个效果就是根据对应的动画变动)

HeadViewPagerTransformer.Java

public class HeadViewPagerTransformer implements PageTransformer{
    private static final float MIN_SCALE = 0.75f; 
    //主要是设置在不同位置上的VIEW的活动动画
    @Override
    public void transformPage(View view, float position) {
        // TODO Auto-generated method stub
         int pageWidth = view.getWidth();  
          
            if (position < -1) { // [-Infinity,-1)   
                view.setAlpha(0);  
            }
            else if (position <= 0) { // [-1,0]  
                view.setAlpha(1);  
                view.setTranslationX(0);  
                float x = -1.0f * (2f / 3f) * pageWidth * position;
                view.setTranslationX(x);  
                float scaleFactor = MIN_SCALE + (2 - MIN_SCALE) * (1 - Math.abs(position)); 
                view.setScaleX(scaleFactor);  
                view.setScaleY(scaleFactor); 
            } else if (position <= 1) { // (0,1]  
                view.setAlpha(1);  
                float x = -1.0f * (2f / 3f) * pageWidth * position;
                view.setTranslationX(x);  
                float scaleFactor = MIN_SCALE + (2 - MIN_SCALE) * (1 - Math.abs(position));  
                view.setScaleX(scaleFactor);  
                view.setScaleY(scaleFactor);  
      
            }
    }

}

因为在这个类中,viewpager中view都有对应的位置编号,在正中间显示的view位置是0

在左边的view位置是-1,在右边的view位置是1.(相当于一个坐标轴)

只要viewpager发生滑动,就会调用tansFromPager();position之说以是float类型,是因为如果发生滑动,位置就会有对应的变化,而变化精确到0.0001.

在函数中使用if-else来设定在不同位置区间中的view的动画变化;

if (position < -1) { // [-Infinity,-1)     
   view.setAlpha(0);    
}  

这是负无穷到-1的区间,当然,如果你的viewpager缓存的view只有三个的话,这个就没有作用了,因为最多只有三个view,多出来就销毁了。

else if (position <= 0) { // [-1,0]  
                view.setAlpha(1);  
                view.setTranslationX(0);  
                float x = -1.0f * (2f / 3f) * pageWidth * position;
                view.setTranslationX(x);  
                float scaleFactor = MIN_SCALE + (2 - MIN_SCALE) * (1 - Math.abs(position)); 
                view.setScaleX(scaleFactor);  
                view.setScaleY(scaleFactor); }

这是-1到0的区间,就是左边的view到中间或中间的view到左边的动画效果,这里主要是做了两个动画变化,一是大小,二是位置。

这两个变化公式是根据位置的变化与动画数值的关系,解二元一次方程求出来的(初中数学知识。。。。)

具体方式就是balbalblabalbalb。。。。。(不多说)

同理

else if (position <= 1) { // (0,1]  
                view.setAlpha(1);  
                float x = -1.0f * (2f / 3f) * pageWidth * position;
                view.setTranslationX(x);  
                float scaleFactor = MIN_SCALE + (2 - MIN_SCALE) * (1 - Math.abs(position));  }

0到1的区间一样。在实际动画设计的过程中,公式是需要变动的。

剩下的都是普通的viewpager使用,设置adapter  (HeadViewPagerAdapter.java)

public class HeadViewPagerAdapter extends PagerAdapter {

    private Context mContext;
    private List<MyImageView> mList;
    
    public HeadViewPagerAdapter(Context context,List<MyImageView> list){
        this.mContext = context;
        this.mList = list;
    }
    
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return mList.size();
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        // TODO Auto-generated method stub
        return arg0 == arg1;
    }
    //当缓存view的数量超过上限时,会销毁最先的一个
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // TODO Auto-generated method stub
        //Log.d("remove", mImageViews[position].hashCode() + "");
        container.removeView(mList.get(position));
    }
    //添加View
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // TODO Auto-generated method stub
        container.addView(mList.get(position),0);
        return mList.get(position);
    }

}

还有就是对应的绑定:HeadViewPager.java

public class HeadViewPager extends FrameLayout {

    private Context mContext;
    private ViewPager mViewPager;
    private List<Integer> mImageIds;
    private List<MyImageView> mImageViews;
    private ViewGroup mViewGroup;
    private List<ImageView> tips;
    private int tipsChoseImgId;
    private int tipsUnchoseImgId;
    
    public HeadViewPager(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        creatView(context);
    }

    public HeadViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        creatView(context);
    }

    public HeadViewPager(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        creatView(context);
    }
    
    public HeadViewPager(Context context,List<MyImageView> imgageList) {
        super(context);
        // TODO Auto-generated constructor stub
        creatView(context,imgageList);
    }
    
    public void creatView(Context context){
        this.mContext = context;
        LayoutInflater.from(context).inflate(R.layout.head_view_pager, this);
        mViewPager = (ViewPager)findViewById(R.id.viewpager);
        mViewGroup = (ViewGroup)findViewById(R.id.viewgroup);
        mImageViews = new ArrayList<MyImageView>();
        mImageIds = new ArrayList<Integer>();
        tips = new ArrayList<ImageView>();
        tipsChoseImgId = R.drawable.img_bg_chose;
        tipsUnchoseImgId = R.drawable.img_bg_unchose;
        build();
    }
    
    public void creatView(Context context,List<MyImageView> imgageList){
        this.mContext = context;
        LayoutInflater.from(context).inflate(R.layout.head_view_pager, this);
        mViewPager = (ViewPager)findViewById(R.id.viewpager);
        mViewGroup = (ViewGroup)findViewById(R.id.viewgroup);
        mImageViews = imgageList;
        mImageIds = new ArrayList<Integer>();
        tips = new ArrayList<ImageView>();
        tipsChoseImgId = R.drawable.img_bg_chose;
        tipsUnchoseImgId = R.drawable.img_bg_unchose;
        build();
    }
    
    public void build(){
        buildTips();
        mViewPager.setAdapter(new HeadViewPagerAdapter(mContext,mImageViews));
        //设置默认显示页面为第0页
        mViewPager.setCurrentItem(0);
        //设置选择页面时的动画
        mViewPager.setPageTransformer(true, new HeadViewPagerTransformer());
        //设置缓存View的个数,默认是3个,这表示缓存了5个
        mViewPager.setOffscreenPageLimit(4);
        //页面发生改变的监听器
        mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
            //选择发生改变
            @Override
            public void onPageSelected(int arg0) {
                // TODO Auto-generated method stub
                changeTips(arg0);
            }
            //有滑动操作
            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // TODO Auto-generated method stub
                
            }
            //滑动操作或选择改变
            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub
                
            }
        });
        
    }
    //初始化底部导航圆点条
    public void buildTips(){
        for (int i = 0 ; i < mImageViews.size() ; i ++){
            ImageView imageView = new ImageView(mContext);  
            imageView.setLayoutParams(new LayoutParams(10,10));   
            if(i == 0){  
                imageView.setBackgroundResource(tipsChoseImgId);  
            }else{  
                imageView.setBackgroundResource(tipsUnchoseImgId);  
            }  
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(12,12));  
            layoutParams.leftMargin = 5;  
            layoutParams.rightMargin = 5;  
            tips.add(imageView); 
            mViewGroup.addView(imageView, layoutParams);  
        }
    }
    //当选定的页面发生改变时,导航条也对应改变
    public void changeTips(int index){
        for (int i = 0 ; i < tips.size() ; i ++){  
            if(i == index){  
                tips.get(i).setBackgroundResource(tipsChoseImgId);  
            }else{  
                tips.get(i).setBackgroundResource(tipsUnchoseImgId);  
            }  
        }
    }

    public Context getmContext() {
        return mContext;
    }

    public void setmContext(Context mContext) {
        this.mContext = mContext;
    }

    public ViewPager getmViewPager() {
        return mViewPager;
    }

    public void setmViewPager(ViewPager mViewPager) {
        this.mViewPager = mViewPager;
    }

    public List<MyImageView> getmImageViews() {
        return mImageViews;
    }
    //改变图片队列时,要更新整个viewPager
    public void setmImageViews(List<MyImageView> mImageViews) {
        this.mImageViews = mImageViews;
        this.mViewPager.notify();
        this.mViewPager.setCurrentItem(0);
        
    }

    public ViewGroup getmViewGroup() {
        return mViewGroup;
    }

    public void setmViewGroup(ViewGroup mViewGroup) {
        this.mViewGroup = mViewGroup;
    }

    public int getTipsChoseImgId() {
        return tipsChoseImgId;
    }

    public void setTipsChoseImgId(int tipsChoseImgId) {
        this.tipsChoseImgId = tipsChoseImgId;
    }

    public int getTipsUnchoseImgId() {
        return tipsUnchoseImgId;
    }

    public void setTipsUnchoseImgId(int tipsUnchoseImgId) {
        this.tipsUnchoseImgId = tipsUnchoseImgId;
    }    
}

样例项目资源:

http://download.csdn.NET/detail/nickey_1314/8932807

点击打开链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现自定义画廊效果,可以通过继承ViewPager类,重写其onInterceptTouchEvent()和onTouchEvent()方法,并在onDraw()方法中绘制自定义效果。 以下是一个简单的实现步骤: 1. 继承ViewPager类,重写onInterceptTouchEvent()和onTouchEvent()方法,用于捕捉和处理触摸事件。 ```java public class GalleryViewPager extends ViewPager { private float mLastMotionX; private int mTouchSlop; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { ViewConfiguration config = ViewConfiguration.get(getContext()); mTouchSlop = config.getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (Math.abs(mLastMotionX - ev.getX()) > mTouchSlop)) { return true; } mLastMotionX = ev.getX(); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } } ``` 2. 在onDraw()方法中绘制自定义效果。例如,可以绘制一个圆形的选中框,并将当前选中的页面放大。 ```java public class GalleryViewPager extends ViewPager { // ... private Paint mPaint; private RectF mRectF; private float mRadius; // 当前选中的页面索引 private int mCurrentPageIndex = 0; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // ... mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(4); mPaint.setColor(Color.WHITE); mRadius = 100; mRectF = new RectF(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (getChildCount() <= 0) { return; } // 绘制圆形选中框 float cx = getWidth() / 2f; float cy = getHeight() / 2f; float x = cx - mRadius; float y = cy - mRadius; mRectF.set(x, y, x + 2 * mRadius, y + 2 * mRadius); canvas.drawOval(mRectF, mPaint); // 放大当前选中的页面 View currentPage = getChildAt(mCurrentPageIndex); float currentScale = 1.2f; float scale = (currentPage.getWidth() * currentScale) / currentPage.getWidth(); currentPage.setScaleX(scale); currentPage.setScaleY(scale); } // ... } ``` 3. 在onPageSelected()方法中更新当前选中的页面索引,并调用invalidate()方法强制重绘。 ```java public class GalleryViewPager extends ViewPager { // ... @Override public void onPageSelected(int position) { mCurrentPageIndex = position; invalidate(); super.onPageSelected(position); } // ... } ``` 最后,使用自定义的GalleryViewPager代替原来的ViewPager即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值