自定义控件实现(淘宝头条/京东快报)垂直循环滚动栏目

1、通过继承LinearLayout的方式

①自定义属性
  
  
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JDAdverView">
<attr name="gap" format="integer" />
<attr name="animDuration" format="integer"/>
</declare-styleable>
</resources>
②自定义View
   
   
public class JDAdverView extends LinearLayout {
//控件高度
private float mAdverHeight = 0f;
//间隔时间
private final int mGap = 4000;
//动画间隔时间
private final int mAnimDuration = 1000;
//显示文字的尺寸
private final float TEXTSIZE = 20f;
private JDViewAdapter mAdapter;
private final float jdAdverHeight = 50;
//显示的view
private View mFirstView;
private View mSecondView;
//播放的下标
private int mPosition;
//线程的标识
private boolean isStarted;
//画笔
private Paint mPaint;
public JDAdverView(Context context) {
this(context, null);
}
public JDAdverView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public JDAdverView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
/**
* 初始化属性
*/
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
//设置为垂直方向
setOrientation(VERTICAL);
//抗锯齿效果
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//获取自定义属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.JDAdverView);
mAdverHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, jdAdverHeight, getResources().getDisplayMetrics());
int gap = array.getInteger(R.styleable.JDAdverView_gap, mGap);
int animDuration = array.getInteger(R.styleable.JDAdverView_animDuration, mAnimDuration);
if (mGap <= mAnimDuration) {
gap = mGap;
animDuration = mAnimDuration;
}
//关闭清空TypedArray 防止内存泄露
array.recycle();
}
/**
* 测量控件的宽高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (LayoutParams.WRAP_CONTENT == getLayoutParams().height) {
getLayoutParams().height = (int) mAdverHeight;
} else {
mAdverHeight = getHeight();
}
 
if (mFirstView != null) {
mFirstView.getLayoutParams().height = (int) mAdverHeight;
}
if (mSecondView != null) {
mSecondView.getLayoutParams().height = (int) mAdverHeight;
}
}
/**
* 画布局
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, TEXTSIZE, getResources().getDisplayMetrics()));
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawText("瑞士维氏军刀", TEXTSIZE, getHeight() * 2 / 3, mPaint);//写文字2/3的高度
}
/**
* 设置数据
*/
public void setAdapter(JDViewAdapter adapter) {
this.mAdapter = adapter;
setupAdapter();
}
/**
* 开启线程
*/
public void start() {
if (!isStarted && mAdapter.getCount() > 1) {
isStarted = true;
postDelayed(mRunnable, mGap);//间隔mgap刷新一次UI
}
}
/**
* 暂停滚动
*/
public void stop() {
//移除handle更新
removeCallbacks(mRunnable);
//暂停线程
isStarted = false;
}
/**
* 设置数据适配
*/
private void setupAdapter() {
//移除所有view
removeAllViews();
//只有一条数据,不滚东
if (mAdapter.getCount() == 1) {
mFirstView = mAdapter.getView(this);
mAdapter.setItem(mFirstView, mAdapter.getItem(0));
addView(mFirstView);
} else {
//多个数据
mFirstView = mAdapter.getView(this);
mSecondView = mAdapter.getView(this);
mAdapter.setItem(mFirstView, mAdapter.getItem(0));
mAdapter.setItem(mSecondView, mAdapter.getItem(1));
//把2个添加到此控件里
addView(mFirstView);
addView(mSecondView);
mPosition = 1;
isStarted = false;
}
}
/**
* 垂直滚蛋
*/
private void performSwitch() {
//属性动画控制控件滚动,y轴方向移动
ObjectAnimator animator1 =ObjectAnimator.ofFloat(mFirstView,"translationY", mFirstView.getTranslationY()- mAdverHeight);
ObjectAnimator animator2 =ObjectAnimator.ofFloat(mSecondView,"translationY",mSecondView.getTranslationY()- mAdverHeight);
//动画集
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1, animator2);//2个动画一起
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {//动画结束
mFirstView.setTranslationY(0);
mSecondView.setTranslationY(0);
View removedView = getChildAt(0);//获得第一个子布局
mPosition++;
//设置显示的布局
mAdapter.setItem(removedView, mAdapter.getItem(mPosition % mAdapter.getCount()));
//移除前一个view
removeView(removedView);
//添加下一个view
addView(removedView, 1);
}
});
set.setDuration(mAnimDuration);//持续时间
set.start();//开启动画
}
private AnimRunnable mRunnable = new AnimRunnable();
private class AnimRunnable implements Runnable {
@Override
public void run() {
performSwitch();
postDelayed(this, mGap);
}
}
/**
* 销毁View的时候调用
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
//停止滚动
stop();
}
/**
* 屏幕 旋转
*/
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
数据适配器
  
  
public class JDViewAdapter {
private List<AdverNotice> mDatas;
public JDViewAdapter(List<AdverNotice> mDatas) {
this.mDatas = mDatas;
if (mDatas == null || mDatas.isEmpty()) {
throw new RuntimeException("nothing to show");
}
}
/**
* 获取数据的条数
*/
public int getCount() {
return mDatas == null ? 0 : mDatas.size();
}
/**
* 获取摸个数据
*/
public AdverNotice getItem(int position) {
return mDatas.get(position);
}
/**
* 获取条目布局
*/
public View getView(JDAdverView parent) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.item, null);
}
/**
* 条目数据适配
*/
public void setItem(final View view, final AdverNotice data) {
TextView tv = (TextView) view.findViewById(R.id.title);
tv.setText(data.title);
TextView tag = (TextView) view.findViewById(R.id.tag);
tag.setText(data.url);
//你可以增加点击事件
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//比如打开url
Toast.makeText(view.getContext(), data.url, Toast.LENGTH_SHORT).show();
}
});
}
}
④条目的布局
   
   
<?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="60dp"
android:background="#ffffff"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tag"
android:textColor="#ff0000"
android:layout_marginLeft="10dp"
android:text="最新"
android:background="@drawable/corner"
android:textSize="18sp"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/title"
android:layout_marginLeft="10dp"
android:singleLine="true"
android:ellipsize="end"
android:textSize="20sp"
android:text="价格惊呆!电信千兆光纤上市"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
⑤代码中使用:
    
    
initData();
final JDViewAdapter adapter = new JDViewAdapter(datas);
final JDAdverView tbView = (JDAdverView) findViewById(R.id.jdadver);
tbView.setAdapter(adapter);
//开启线程滚东
tbView.start();
   
   
private void initData() {
datas.add(new AdverNotice("瑞士维氏军刀 新品满200-50","最新"));
datas.add(new AdverNotice("家居家装焕新季,讲199减100!","最火爆"));
datas.add(new AdverNotice("带上相机去春游,尼康低至477","HOT"));
datas.add(new AdverNotice("价格惊呆!电信千兆光纤上市","new"));
}

2、ViewFlipper实现

  
  
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoStart="true"
android:flipInterval="900" //设置滚动的时间
android:inAnimation="@anim/push_up_in"    //切入动画
android:outAnimation="@anim/push_up_out" >//切出动画
<include layout="@layout/news_one" />
<include layout="@layout/news_two" />
<include layout="@layout/news_three" />
<include layout="@layout/news_four"/>
</ViewFlipper>

3、TextSwitcher实现

   
   
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/bg"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:text="京东"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff0000"
android:padding="5dp"
android:paddingLeft="5dp"
android:text="快报"
android:textColor="#ffffff"
android:textSize="16sp"
android:textStyle="bold" />
<View
android:layout_width="1dp"
android:layout_height="50dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#e0e0e0" />
<!-- flipInterval可能是一次切换的时间 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextSwitcher
android:id="@+id/textSwitcher_tag"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_weight="3"
android:padding="0dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:inAnimation="@anim/push_up_in"
android:outAnimation="@anim/push_up_out">
</TextSwitcher>
<TextSwitcher
android:id="@+id/textSwitcher_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_weight="1"
android:padding="0dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:inAnimation="@anim/push_up_in"
android:outAnimation="@anim/push_up_out">
</TextSwitcher>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

   
   
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textSwitcher_tag= (TextSwitcher) findViewById(R.id.textSwitcher_tag);
textSwitcher_title= (TextSwitcher) findViewById(R.id.textSwitcher_title);
textSwitcher_title.setFactory(new ViewSwitcher.ViewFactory() {
@Override
public View makeView() {
final TextView tv = new
TextView(MainActivity.this);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
tv.setPadding(20, 20, 20, 20);
return tv;
}
});
textSwitcher_tag.setFactory(new ViewSwitcher.ViewFactory() {
@Override
public View makeView() {
final TextView tv = new
TextView(MainActivity.this);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
tv.setPadding(30, 20, 20,20);
tv.setTextColor(Color.RED);
tv.setBackgroundResource(R.drawable.corner);
return tv;
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
textSwitcher_tag.setText(tags[curStr++ %tags.length]);
textSwitcher_title.setText(titles[curStr++ % titles.length]);
handler.postDelayed(this, 1000);
}
}, 1000);
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值