仿 淘宝头条热点 天猫头条热点 京东头条热点的自定义view 实现

最近整理了一下在自己负责的项目中用到的一些自定义View 实现一些比较热门的功能,写到这里给自己留一份笔记,同时给那些有需要的朋友!

Demo主要是重写了一下Linearlayout,对其填充你想要填充的布局,由于在代码中都添加了注释,这里不再做一一解释了

先看看效果图:

自定义View:

package com.example.nostalgia.myapplication.view;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

import com.example.nostalgia.myapplication.R;
import com.example.nostalgia.myapplication.Utils.DensityUtils;
import com.example.nostalgia.myapplication.bean.NewsInfo;

import java.util.List;

/**
 * Created by Nostalgia on 2016/12/8.
 * Title : 头条热点
 */
public class HomeScrollTopView extends LinearLayout {

    private Scroller mScroller;  //滚动实例
    private int size = 0;

    private List<NewsInfo> list;  //存放数据集合
    private final int DURING_TIME = 3000;  //滚动延迟
    private OnAdapterClickListener<NewsInfo> click;
    Context context;

    public HomeScrollTopView(Context context) {
        super(context);
        this.context = context;
        init();
    }

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

    private void init() {
        mScroller = new Scroller(getContext());
    }

    /**
     * 设置数据
     *
     * @param list
     */
    public void setData(List<NewsInfo> list) {
        this.list = list;
        if (list != null) {
            removeAllViews();
            size = list.size();
            for (int i = 0; i < size; i++) {
                addContentView(i);
            }
            if (list.size() > 1) {
                getLayoutParams().height = DensityUtils.dip2px(context, 40);//调节滚动数据的高度
                // 滚动
                cancelAuto();
                mHandler.sendEmptyMessageDelayed(0, DURING_TIME);
                smoothScrollBy(0, DensityUtils.dip2px(context, 40));
            }
        }
    }

    /**
     * 设置列表点击事件
     *
     * @param click
     */
    public void setClickListener(OnAdapterClickListener<NewsInfo> click) {
        this.click = click;
    }

    /**
     * 重置数据
     */
    private void resetView() {
        NewsInfo homeBuyHouseGuide = list.get(0);
        list.remove(0);
        list.add(homeBuyHouseGuide);

        for (int i = 0; i < size; i++) {
            addContentView(i);
        }
    }

    /**
     * 取消滚动
     */
    public void cancelAuto() {
        mHandler.removeMessages(0);
    }

    private void addContentView(final int position) {
        ViewHolder mHolder;
        if (position >= getChildCount()) {
            mHolder = new ViewHolder();
            View v = View.inflate(getContext(), R.layout.home_scrolltopview, null);
            mHolder.biaoqianTv = (TextView) v.findViewById(R.id.tv_biaoqian);
            mHolder.nameTv = (TextView) v.findViewById(R.id.tv);
            v.setTag(mHolder);
            addView(v, LayoutParams.MATCH_PARENT, DensityUtils.dip2px(context, 40));
        } else {
            mHolder = (ViewHolder) getChildAt(position).getTag();
        }
        final NewsInfo newsInfo = list.get(position);
        if (!DensityUtils.isNullOrEmpty(newsInfo.tagname)) {
            mHolder.biaoqianTv.setText(newsInfo.tagname);
        } else {
            mHolder.biaoqianTv.setVisibility(GONE);
        }
        if (!DensityUtils.isNullOrEmpty(newsInfo.title)) {
            mHolder.nameTv.setText(newsInfo.title);
        } else {
            mHolder.nameTv.setVisibility(GONE);
        }
        mHolder.nameTv.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                if (click != null) {
                    click.onAdapterClick(null, newsInfo);
                }
            }
        });
    }

    private class ViewHolder {
        TextView nameTv;
        TextView biaoqianTv;
    }

    Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            mHandler.removeMessages(0);
            mHandler.sendEmptyMessageDelayed(0, DURING_TIME);
            smoothScrollBy(0, DensityUtils.dip2px(context, 40));
            resetView();
        }

        ;
    };

    // 调用此方法设置滚动的相对偏移
    public void smoothScrollBy(int dx, int dy) {
        // 设置mScroller的滚动偏移量
        mScroller.startScroll(mScroller.getFinalX(), 0, dx, dy, DURING_TIME);
        invalidate();// 这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
    }

    @Override
    public void computeScroll() {

        // 先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {

            // 这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            // 必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();

        }
        super.computeScroll();
    }

    public interface OnAdapterClickListener<T> {
        public void onAdapterClick(View v, T t);
    }
}
实体类:

package com.example.nostalgia.myapplication.bean;

import java.io.Serializable;

/**
 *         Created by
 *          Nostalgia
 *        on 2016/12/8.
 *
 *       Title: 实体类
 */
public class NewsInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    public String type;// 类型 根据type值做跳转使用

    public String tagname;// 标签

    public String title;// 显示标题

    public String news_url;//跳转wap的信息url

    public NewsInfo(String type,String tagname,String title,String news_url) {
        super();
        this.type = type ;
        this.tagname = tagname ;
        this.title = title ;
        this.news_url = news_url ;
    }
}

调用主类:

package com.example.nostalgia.myapplication;


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.example.nostalgia.myapplication.bean.NewsInfo;
import com.example.nostalgia.myapplication.view.HomeScrollTopView;

import java.util.ArrayList;

/**
 * Created by Nostalgia on 2016/12/8.
 * Title : 轮播头条样例
 */
public class MainActivity extends Activity {
    HomeScrollTopView topView;
    LinearLayout ll_homescrolltopview;
    private ArrayList<NewsInfo> newsInfoList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initOper();
    }

    private void initView() {
        topView = (HomeScrollTopView) findViewById(R.id.homescrolltopview);
        ll_homescrolltopview = (LinearLayout) findViewById(R.id.ll_homescrolltopview);
        ll_homescrolltopview.setVisibility(View.GONE);
    }

    private void initData() {
        if (newsInfoList.size() > 0) {
            newsInfoList.clear();
        }
        for (int i = 0; i < 6; i++) {
            newsInfoList.add(new NewsInfo("" + i, "标签" + i, "这里是测试标题" + i, ""));
        }
        /**
         * 上面改成接口返回的数据填充到list中
         */
        if (newsInfoList.size() < 1) {
            ll_homescrolltopview.setVisibility(View.GONE);
        } else {
            ll_homescrolltopview.setVisibility(View.VISIBLE);
            topView.setData(newsInfoList);
        }
    }

    private void initOper() {
        topView.setClickListener(new HomeScrollTopView.OnAdapterClickListener<NewsInfo>() {
            @Override
            public void onAdapterClick(View v, NewsInfo newsInfo) {
                if ("1".equals(newsInfo.type)) {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname +"\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                } else if ("2".equals(newsInfo.type)) {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname + "\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                } else if ("3".equals(newsInfo.type)) {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname + "\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                } else if ("4".equals(newsInfo.type)) {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname + "\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                } else if ("5".equals(newsInfo.type)) {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname + "\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "标签:" + newsInfo.tagname + "\n标题:" + newsInfo.title, Toast.LENGTH_SHORT).show();
                }
            }
        });
    }


}
工具方法:

  /**
     * dp转px
     *
     * @param context
     * @param
     * @return
     */
    public static int dip2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
    }


    /**
     * 判断是否为空
     *
     * @param text
     * @return
     */
    public static boolean isNullOrEmpty(String text) {
        if (text == null || "".equals(text.trim()) || text.trim().length() == 0
                || "null".equals(text.trim())) {
            return true;
        } else {
            return false;
        }
    }

Demo代码已完整上传到CSDN: 点这里去下载

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值