上下滚动垂直轮播

京东首页快报有一个上下滚动的快报功能:
在这里插入图片描述

这种功能Android本身提供有相应的组建ViewSwitcher实现。昨晚看了一下ViewSwitcher的原理写了一个类似的功能。
原理:

  • 1.ViewSwitcher本身是一个FrameLayout控件;
  • 2.通过接口ViewFactory中的makeView方法把我们需要的布局样式View传递进;
  • 3.添加布局进出动画转场;
  • 4.添加时间任务不断切换布局View。

具体代码如下:
1.新建继承ViewSwitcher的类AutoVerticalScrollView:

package com.fml.practice;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ViewSwitcher;
import com.fml.home.R;
import com.linxz.core.protocol.image.ImageLoader;
import com.linxz.fml.pojo.user.UserInfo;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Linxz
 * 创建日期:2019年04月30日 23:04
 * version:1.0.0
 * 描述:
 */
public class AutoVerticalScrollView extends ViewSwitcher implements ViewSwitcher.ViewFactory{
    private final static int SWITCH_FLAG=1002;
    private Context mContext;
    private Rotate3dAnimation mInUp;
    private Rotate3dAnimation mOutUp;

    private int mDelayMillis=3000;
    private int mSwitchCount=0;
    private List<UserInfo> userInfos=new ArrayList<>();
    private OnScrollViewItemClickListener mOnScrollViewItemClickListener;

    public AutoVerticalScrollView(Context context) {
        super(context);
        this.mContext=context;
    }

    public AutoVerticalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext=context;
        init();
    }

    private void init() {
        setFactory(this);
        mInUp = createAnim(true, true);
        mOutUp = createAnim(false, true);
        setInAnimation(mInUp);//当View显示时动画资源ID
        setOutAnimation(mOutUp);//当View隐藏是动画资源ID。
    }

    private Rotate3dAnimation createAnim(boolean turnIn, boolean turnUp) {
        Rotate3dAnimation rotation = new Rotate3dAnimation(turnIn, turnUp);
        rotation.setDuration(1200);//执行动画的时间
        rotation.setFillAfter(false);//是否保持动画完毕之后的状态
        rotation.setInterpolator(new AccelerateInterpolator());//设置加速模式
        return rotation;
    }

    @SuppressLint("InflateParams")
    @Override
    public View makeView() {
        View view=LayoutInflater.from(mContext).inflate(R.layout.view_switcher,null);
        return view;
    }

    public void setmOnScrollViewItemClickListener(OnScrollViewItemClickListener onScrollViewItemClickListener){
        this.mOnScrollViewItemClickListener=onScrollViewItemClickListener;
    }

    private Runnable mRunnable=new Runnable() {
        @Override
        public void run() {
            Message message=new Message();
            message.what=SWITCH_FLAG;
            mHandler.sendMessage(message);
            mHandler.postDelayed(mRunnable,mDelayMillis);
        }
    };

    @SuppressLint("HandlerLeak")
    private Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==SWITCH_FLAG){
                next();
                mSwitchCount++;
                UserInfo userInfo=userInfos.get(mSwitchCount%userInfos.size());
                updateView(userInfo);
            }
        }
    };


    private void next(){
        if (getInAnimation()!=mInUp){
            setInAnimation(mInUp);
        }
        if (getOutAnimation()!=mOutUp){
            setOutAnimation(mOutUp);
        }
    }

    private void updateView(final UserInfo userInfo){
        View view=getNextView();
        ImageView mImgUser=view.findViewById(R.id.imgUser);
        TextView mTvUserName=view.findViewById(R.id.tvUserName);
        TextView mTvUserSign=view.findViewById(R.id.tvSign);
        getCurrentView().setTag(userInfo);
        ImageLoader.build()
                .load(userInfo.getHeadimg())
                .context(mContext)
                .placeholder(R.drawable.icon_sale)
                .error(R.drawable.icon_sale)
                .into(mImgUser);
        mTvUserName.setText(userInfo.getName());
        mTvUserSign.setText(userInfo.getSign());
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                UserInfo info= (UserInfo) v.getTag();
                if (info!=null && mOnScrollViewItemClickListener!=null){
                    mOnScrollViewItemClickListener.onClick(userInfo);
                }
            }
        });
        showNext();
    }

    public void start(List<UserInfo> userInfos){
        if (userInfos==null){
            throw new IllegalArgumentException("params can not be null!!!");
        }
        if (userInfos.size()<=0){
            return;
        }
        this.userInfos=userInfos;
        updateView(userInfos.get(0));
        mHandler.postDelayed(mRunnable,mDelayMillis);
    }

    class Rotate3dAnimation extends Animation {
        private float mCenterX;
        private float mCenterY;
        private final boolean mTurnIn;
        private final boolean mTurnUp;
        private Camera mCamera;

        private Rotate3dAnimation(boolean turnIn, boolean turnUp) {
            mTurnIn = turnIn;
            mTurnUp = turnUp;
        }

        @Override
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mCamera = new Camera();
            mCenterY = getHeight();
            mCenterX = getWidth();
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {

            final float centerX = mCenterX;
            final float centerY = mCenterY;
            final Camera camera = mCamera;
            final int derection = mTurnUp ? 1 : -1;

            final Matrix matrix = t.getMatrix();

            camera.save();
            if (mTurnIn) {
                camera.translate(0.0f, derection * mCenterY * (interpolatedTime - 1.0f), 0.0f);
            } else {
                camera.translate(0.0f, derection * mCenterY * (interpolatedTime), 0.0f);
            }
            camera.getMatrix(matrix);
            camera.restore();

            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
        }
    }

    public interface OnScrollViewItemClickListener{
         void onClick(UserInfo userInfo);
    }

}

2.定义的实体类:

package com.linxz.fml.pojo.user;

/**
 * @author Linxz
 * 创建日期:2019年03月01日 16:24
 * version:1.0.0
 * 描述:
 */
public class UserInfo {

    private String headimg;
    private String phone;
    private String sex;
    private String name;
    private String sign;
    private String rank;
    private String adress;
    private String userId;
    private String email;
    private String token;

    public String getHeadimg() {
        return headimg;
    }

    public void setHeadimg(String headimg) {
        this.headimg = headimg;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public Object getRank() {
        return rank;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }

    public String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

3.新建ViewFactory接口中makeView方法需要的布局view_switcher.xml(根据具体需求去定义)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="15dp"
    android:background="@color/white">

    <com.linxz.ui.widgets.CircleImageView
        android:id="@+id/imgUser"
        android:src="@drawable/icon_sale"
        android:layout_width="45dp"
        android:layout_height="45dp" />

    <TextView
        android:layout_toRightOf="@+id/imgUser"
        android:layout_marginLeft="20dp"
        android:id="@+id/tvUserName"
        android:text="用户名"
        android:textSize="14sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="HardcodedText,RtlHardcoded" />
    <TextView
        android:id="@+id/tvSign"
        android:layout_toRightOf="@+id/imgUser"
        android:layout_below="@+id/tvUserName"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="20dp"
        android:textSize="12sp"
        android:text="这个人很懒,什么也没有留下"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="HardcodedText,RtlHardcoded" />

</RelativeLayout>

4.自定义View AutoVerticalScrollView的使用:
布局home_practice_act_autoverticalscrollview.xml中

<?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">
    <com.fml.practice.AutoVerticalScrollView
        android:id="@+id/autoScrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

Activity中

package com.fml.practice;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.fml.home.R;
import com.linxz.fml.pojo.user.UserInfo;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Linxz
 * 创建日期:2019年04月30日 23:46
 * version:1.0.0
 * 描述:
 */
public class AutoVerticalScrollViewActivity extends AppCompatActivity {
    private AutoVerticalScrollView mAutoScrollView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.home_practice_act_autoverticalscrollview);
        mAutoScrollView=findViewById(R.id.autoScrollView);
        mAutoScrollView.setmOnScrollViewItemClickListener(new AutoVerticalScrollView.OnScrollViewItemClickListener() {
            @Override
            public void onClick(UserInfo userInfo) {
                Toast.makeText(AutoVerticalScrollViewActivity.this,userInfo.getName(),Toast.LENGTH_SHORT).show();
            }
        });
        List<UserInfo> userInfos=new ArrayList<>();
        for (int i=0;i<10;i++){
            UserInfo userInfo=new UserInfo();
            userInfo.setHeadimg("http://pic37.nipic.com/20140110/17563091_221827492154_2.jpg");
            userInfo.setName("张三丰"+i);
            userInfo.setSign("AADADFDFAF");
            userInfos.add(userInfo);
        }
        mAutoScrollView.start(userInfos);
    }
}

运行效果如下:
在这里插入图片描述

这就实现了类似京东首页快报的功能。
注:在原本的代码中我本来是想为了防止轮播过程中不断实例化userImageView,tvUserName,tvSign,写为全局变量,在makeView的时候进行初始化,之后每次切换的时候就给这些控件设置新的UserInfo数据来进行刷新,但是这样做页面却没有更新数据,主动强制更新UI也不行,还没搞懂为什么。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值