Android实例(一)—— 3D画廊

作者: python草莓 | 来源:发表于2019-04-12 20:37 被阅读1次

    3D画廊

    之前我都是写的学习的内容,我在写这些教程时遇到有趣的炫酷的小例子也会专门拿出来写一篇文章,今天就写一个酷炫的小例子,叫3D画廊,它是属于ViewPage的进阶版。

    此项目下载地点:https://github.com/qySvip/3D-gallery

    下面的指示器是使用的一大神的第三方库,会在文章下方简单讲述一下。

    效果图

    image

    3D画廊的实现

    首先是布局文件

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:clipChildren="false"
        android:background="@android:color/black"
        android:id="@+id/frame_layout">
    
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="450dp"
            android:layout_gravity="center"
            android:id="@+id/gallery"
            android:clipChildren="false"
            android:layout_marginLeft="85dp"
            android:layout_marginRight="85dp" />
    
            <com.lwj.widget.viewpagerindicator.ViewPagerIndicator
                android:id="@+id/indicator_circle_line"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_gravity="bottom"
                android:background="#efefef"
                app:vpi_default_color="#FF239AF5"
                app:vpi_distance="60dp"
                app:vpi_distanceType="BY_LAYOUT"
                app:vpi_indicatorType="CIRCLE_LINE"
                app:vpi_radius="10dp"
                app:vpi_selected_color="#FF239AF5"
                />
    
    </FrameLayout>
    

    代码中的ViewPagerIndicator是用于实现下方的指示器,这个我们在最后在进行解释;

    首先布局使用帧布局,内部用到ViewPager控件,注意在ViewPager控件的父布局中我们要添加android:clipChildren="false"属性,它的作用是定义它的子控件是否要在它应有的边界内进行绘制,默认值为true。我们这里要用false。

    然后在ViewPager中用到android:layout_marginLeft和android:layout_marginRight属性,值不能太大,过大会导致看不到两边的图像,具体根据自己满意进行调整。高度属性为图片和倒影的加起来的高度,自己进行调整。

    GalleryPageTransformer类

    package sample.sdk.qy.com.demo;
    
    import android.support.v4.view.ViewPager;
    import android.view.View;
    
    public class GalleryPageTransformer implements ViewPager.PageTransformer {
        private static final float MAX_ROTATION=20.0f;
        private static final float MIN_SCALE=0.75f;
        private static final float MAX_TRANSLATE=20.0f;
    
        @Override
        public void transformPage(View page, float position) {
            if(position<-1) {
                page.setTranslationX(MAX_TRANSLATE);
                page.setScaleX(MIN_SCALE);
                page.setScaleY(MIN_SCALE);
                page.setRotationY(-MAX_ROTATION);
            }
            else if(position<=0) {
                page.setTranslationX(-MAX_TRANSLATE*position);
                float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f+position);
                page.setScaleX(scale);
                page.setScaleY(scale);
                page.setRotationY(MAX_ROTATION*position);
            }
            else if(position<=1) {
                page.setTranslationX(-MAX_TRANSLATE*position);
                float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f-position);
                page.setScaleX(scale);
                page.setScaleY(scale);
                page.setRotationY(MAX_ROTATION*position);
            }
            else {
                page.setTranslationX(-MAX_TRANSLATE);
                page.setScaleX(MIN_SCALE);
                page.setScaleY(MIN_SCALE);
                page.setRotationY(MAX_ROTATION);
            }
        }
    }
    

    PageTransformer是ViewPager内部定义的接口,这个接口主要用于控制ViewPager中item view的滑动效果。

    • setTranslationX 设置view相对原始位置的水平偏移量
    • setScaleX 设置水平缩放的基准点
    • setScaleY 设置竖直缩放的基准点
    • setRotationY 设置竖直的选择的基准点

    ImageUtils类

    package sample.sdk.qy.com.demo;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.LinearGradient;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Shader;
    
    public class ImageUtils {
        public static Bitmap getReverseBitmapById(Context context, int resId, float percent) {
            // get the source bitmap
            Bitmap srcBitmap= BitmapFactory.decodeResource(context.getResources(), resId);
            // get the tow third segment of the reverse bitmap
            Matrix matrix=new Matrix();
            matrix.setScale(1, -1);
            Bitmap rvsBitmap=Bitmap.createBitmap(srcBitmap, 0, (int) (srcBitmap.getHeight()*(1-percent)),
                    srcBitmap.getWidth(), (int) (srcBitmap.getHeight()*percent), matrix, false);
            // combine the source bitmap and the reverse bitmap
            Bitmap comBitmap=Bitmap.createBitmap(srcBitmap.getWidth(),
                    srcBitmap.getHeight()+rvsBitmap.getHeight()+20, srcBitmap.getConfig());
            Canvas gCanvas=new Canvas(comBitmap);
            gCanvas.drawBitmap(srcBitmap, 0, 0, null);
            gCanvas.drawBitmap(rvsBitmap, 0, srcBitmap.getHeight()+20, null);
            Paint paint=new Paint();
            LinearGradient shader=new LinearGradient(0, srcBitmap.getHeight()+20, 0, comBitmap.getHeight(),
                    Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
            paint.setShader(shader);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            gCanvas.drawRect(0, srcBitmap.getHeight()+20, srcBitmap.getWidth(), comBitmap.getHeight(), paint);
            return comBitmap;
        }
    }
    

    这是做图片倒影的方法,内部使用了Canvas和Bitmap类,这些后面会进行讲述。

    ViewAdapter类

    package sample.sdk.qy.com.demo;
    
    import android.support.v4.view.PagerAdapter;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.List;
    
    public class ViewAdapter extends PagerAdapter {
        private List<View> datas;
    
        public ViewAdapter(List<View> list) {
            datas=list;
        }
    
        @Override
        public int getCount() {
            return datas.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view==object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view=datas.get(position);
            container.addView(view);
            return view;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(datas.get(position));
        }
    }
    

    适配器类,这里的适配方式为图片和倒影一同进行适配。

    MainActivity类

    package sample.sdk.qy.com.demo;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    
    import com.lwj.widget.viewpagerindicator.ViewPagerIndicator;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends Activity {
    
        private List<View> pages;
        private FrameLayout layout;
        private ViewPager pager;
        private ViewPagerIndicator mIndicatorCircleLine;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            pages=getPages();
            pager=(ViewPager) findViewById(R.id.gallery);
            PagerAdapter adapter=new ViewAdapter(pages);
            pager.setAdapter(adapter);
            pager.setPageMargin(20);
            pager.setOffscreenPageLimit(3);
            pager.setPageTransformer(true, new GalleryPageTransformer());
    
            layout=(FrameLayout) findViewById(R.id.frame_layout);
            layout.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return pager.dispatchTouchEvent(event);
                }
            });
    
            mIndicatorCircleLine = (ViewPagerIndicator) findViewById(R.id.indicator_circle_line);
            mIndicatorCircleLine.setViewPager(pager,9);
        }
    
        private List<View> getPages() {
            List<View> pages=new ArrayList<>();
            Field[] fields=R.drawable.class.getDeclaredFields();
            try {
                for (Field field : fields) {
                    if (field.getName().startsWith("page")) {
                        ImageView view = new ImageView(this);
                        view.setImageBitmap(ImageUtils.getReverseBitmapById(this, field.getInt(null), 0.5f));
                        pages.add(view);
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return pages;
        }
    }
    

    主界面方法,主要用于填充入图片、适配器适配。这里填充图片的方法为在drawable文件中查找以page开头的图片进行填充。

    到这里3D画廊就完成了。。。。。。。。。

    指示器

    下面来说一下指示器的做法,用的是网上一大神的第三方类。

    使用方法:

    1、在 project的build.gradle 添加:

    allprojects { repositories { ... maven { url "https://jitpack.io" } } }

    2、在module的build.gradle 添加:

    dependencies {implementation 'com.github.LinweiJ:ViewPagerIndicator:0.1.0' }

    注意这里要用implementation,compile现在已被废弃,官方显示将在2018年年底删除。

    3、将ViewPagerIndicator控件添加到布局文件。

    属性:

    • app:vpi_selected_color
    • app:vpi_default_color (如果 indicatorType=CIRCLE_LINE default_color 为指示器唯一颜色 ,selected_color 不起作用)
    • app:vpi_radius (点的大小,在indicatorType= CIRCLE_LINE 的情况下 radius 是点的高)
    • app:vpi_length (只作用在 indicatorType=CIRCLE_LINE 的情况下,为 指示器点的长度)
    • app:vpi_distance (只作用在 distanceType=BY_DISTANCE 的情况下)
    • app:vpi_num
    • app:vpi_indicatorType (LINE; CIRCLE; CIRCLE_LINE; BEZIER;SPRING)LINE:线 ; CIRCLE:圆点(默认) ; CIRCLE_LINE:圆角矩形; BEZIER:弹性球 ; SPRING: 弹簧粘性球
    • app:vpi_distanceType (BY_RADIUS; BY_DISTANCE ; BY_LAYOUT )BY_RADIUS:3倍radius ; BY_DISTANCE :定义固定距离 ;BY_LAYOUT :根据layout_width均分得到距离
    • app:vpi_animation(默认为true:动画开启 ; false:关闭动画)

    4、在java文件中初始化该控件

    使用mIndicatorCircleLine.setViewPager(pager,9);,第一个参数为适配器,第二个参数为图片的个数。

    有兴趣的可以加群交流技术【Android技术交流】:https://jq.qq.com/?_wv=1027&k=55YgqsK。进群 免费领取安卓进阶学习视频,源码,面试资料,群内有大牛一起交流讨论技术;点击链接加入群聊(包括java基础与原理,自定义控件、NDK、架构设计、混合式开发(Flutter,Weex)、性能优化、完整商业项目开发等)

    相关文章

      网友评论

        本文标题:Android实例(一)—— 3D画廊

        本文链接:https://www.haomeiwen.com/subject/oencwqtx.html