(气泡动画)水平HorizontalScrollView使用

最近,整理了一些小功能;做了一个水平HorizontalScrollView的demo;现在分享给大家看看
先把需要的图片也提供出来,方便想学得可以尝试,体验:
一张是时间轴,一张是气泡;
时间轴 气泡
先定义一个DemoHorizontalScrollView.java文件;

package com.example.demohorizontalscrollview;
import java.util.HashMap;
import java.util.Map;
import android.view.View.OnClickListener;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class DemoHorizontalScrollView extends HorizontalScrollView  {  
    /** 
     * 图片滚动时的回调接口   
     */  
    public interface CurrentImageChangeListener  
    {  
        void onCurrentImgChanged(int position, View viewIndicator);  
    }  

    private CurrentImageChangeListener mListener;  

    /** 
     * HorizontalListView中的LinearLayout 
     */  
    private LinearLayout mContainer;  

    /** 
     * 子元素的宽度 
     */  
    private int mChildWidth;  
    /** 
     * 子元素的高度 
     */  
    private int mChildHeight;  
    /** 
     * 当前最后一张图片的index 
     */  
    private int mCurrentIndex;  
    /** 
     * 当前第一张图片的下标 
     */  
    private int mFristIndex;  

    /** 
     * 数据适配器 
     */  
    private HorizontalScrollViewAdapter mAdapter;  
    /** 
     * 每屏幕最多显示的个数 
     */  
    private int mCountOneScreen;  
    /** 
     * 屏幕的宽度 
     */  
    private int mScreenWitdh;  


    /** 
     * 保存View与位置的键值对 
     */  
    private Map<View, Integer> mViewPos = new HashMap<View, Integer>();  

    public DemoHorizontalScrollView(Context context, AttributeSet attrs)  
    {  
        super(context, attrs);  
        // 获得屏幕宽度  
        WindowManager wm = (WindowManager) context  
                .getSystemService(Context.WINDOW_SERVICE);  
        DisplayMetrics outMetrics = new DisplayMetrics();  
        wm.getDefaultDisplay().getMetrics(outMetrics);  
        mScreenWitdh = outMetrics.widthPixels;  
    }  

    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    {  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
        mContainer = (LinearLayout) getChildAt(0);  
    }  

    /** 
     * 加载下一张图片 
     */  
    protected void loadNextImg()  
    {  
        // 数组边界值计算  
        if (mCurrentIndex == mAdapter.getCount() - 1)  
        {  
            return;  
        }  
        //移除第一张图片,且将水平滚动位置置0  
        scrollTo(0, 0);  
        mViewPos.remove(mContainer.getChildAt(0));  
        mContainer.removeViewAt(0);  

        //获取下一张图片,并且设置onclick事件,且加入容器中  
        View view = mAdapter.getView(++mCurrentIndex, null, mContainer);  
        mContainer.addView(view);  
        mViewPos.put(view, mCurrentIndex);  

        //当前第一张图片小标  
        mFristIndex++;  
        //如果设置了滚动监听则触发  
        if (mListener != null)  
        {  
            notifyCurrentImgChanged();  
        }  
    }  
    /** 
     * 加载前一张图片 
     */  
    protected void loadPreImg()  
    {  
        //如果当前已经是第一张,则返回  
        if (mFristIndex == 0)  
            return;  
        //获得当前应该显示为第一张图片的下标  
        int index = mCurrentIndex - mCountOneScreen;  
        if (index >= 0)  
        {  
            //移除最后一张  
            int oldViewPos = mContainer.getChildCount() - 1;  
            mViewPos.remove(mContainer.getChildAt(oldViewPos));  
            mContainer.removeViewAt(oldViewPos);  

            //将此View放入第一个位置  
            View view = mAdapter.getView(index, null, mContainer);  
            mViewPos.put(view, index);  
            mContainer.addView(view, 0);  
            //水平滚动位置向左移动view的宽度个像素  
            scrollTo(mChildWidth, 0);  
            //当前位置--,当前第一个显示的下标--  
            mCurrentIndex--;  
            mFristIndex--;  
            //回调  
            if (mListener != null)  
            {  
                notifyCurrentImgChanged();  
            }  
        }  
    }  

    /** 
     * 滑动时的回调 
     */  
    public void notifyCurrentImgChanged()  
    {  
        //先清除所有的背景色,点击时会设置为蓝色  
        for (int i = 0; i < mContainer.getChildCount(); i++)  
        {  
            mContainer.getChildAt(i).setBackgroundColor(Color.WHITE);  
        }  
        mListener.onCurrentImgChanged(mFristIndex, mContainer.getChildAt(0));  
    }  

    /** 
     * 初始化数据,设置数据适配器 
     *  
     * @param mAdapter 
     */  
    public void initDatas(HorizontalScrollViewAdapter mAdapter)  
    {  
        this.mAdapter = mAdapter;  
        mContainer = (LinearLayout) getChildAt(0);  
        // 获得适配器中第一个View  
        final View view = mAdapter.getView(0, null, mContainer);  
        mContainer.addView(view);  
        // 强制计算当前View的宽和高  
        if (mChildWidth == 0 && mChildHeight == 0)  
        {  
            int w = View.MeasureSpec.makeMeasureSpec(0,  
                    View.MeasureSpec.UNSPECIFIED);  
            int h = View.MeasureSpec.makeMeasureSpec(0,  
                    View.MeasureSpec.UNSPECIFIED);  
            view.measure(w, h);  
            mChildHeight = view.getMeasuredHeight();  
            mChildWidth = view.getMeasuredWidth();  
            mChildHeight = view.getMeasuredHeight();  
            // 计算每次加载多少个View  
            mCountOneScreen = mScreenWitdh / mChildWidth+2;  
        }  
        //初始化第一屏幕的元素  
        initFirstScreenChildren(mCountOneScreen);  
    }  

    /** 
     * 加载第一屏的View 
     *  
     * @param mCountOneScreen 
     */  
    public void initFirstScreenChildren(int mCountOneScreen)  
    {  
        mContainer = (LinearLayout) getChildAt(0);  
        mContainer.removeAllViews();  
        mViewPos.clear();  
        for (int i = 0; i < mCountOneScreen; i++)  
        {  
            View view = mAdapter.getView(i, null, mContainer);  
            mContainer.addView(view);  
            mViewPos.put(view, i);  
            mCurrentIndex = i;  
        }  
        if (mListener != null)  
        {  
            notifyCurrentImgChanged();  
        }  
    }  
    @Override  
    public boolean onTouchEvent(MotionEvent ev)  
    {  
        switch (ev.getAction())  
        {  
        //拖动时的事件处理
        case MotionEvent.ACTION_MOVE:  
            int scrollX = getScrollX();  
            // 如果当前scrollX为view的宽度,加载下一张,移除第一张  
            if (scrollX >= mChildWidth)  
            {  
                loadNextImg();  
            }  
            // 如果当前scrollX = 0, 往前设置一张,移除最后一张  
            if (scrollX == 0)  
            {  
                loadPreImg();  
            }  
            break;  
        }  
        return super.onTouchEvent(ev);  
    }  
}  

布局xml中,

<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:layout_marginTop="150dp"
    tools:context=".MainActivity" >  <com.example.demohorizontalscrollview.DemoHorizontalScrollView
        android:id="@+id/id_horizontalScrollView" 
        android:layout_width="fill_parent"
        android:layout_height="120dp"
        android:scrollbars="none" >

        <LinearLayout
            android:id="@+id/horizontal_sv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:orientation="horizontal" >         
        </LinearLayout>   </com.example.demohorizontalscrollview.DemoHorizontalScrollView>
</RelativeLayout>

Horizontalscrollview的子条目的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"
    android:layout_marginLeft="7dp"
    android:layout_marginRight="7dp"
    android:orientation="vertical" >
<LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="3dp" 
    android:orientation="vertical" >
    <TextView
        android:id="@+id/tv_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@drawable/bubble"
        android:gravity="center"
        android:layout_marginTop="10dp"
        android:paddingBottom="5dp"
        android:text="22"
        android:textColor="#ffffff"
        android:textSize="12sp" />

    <ImageView
        android:id="@+id/iv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@drawable/time_bg" >
    </ImageView>

    <TextView
        android:id="@+id/tv_date_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text=""
        android:textColor="#999999"
        android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

另外,再给DemoHorizontalScrollView添加个适配器HorizontalScrollViewAdapter.java

package com.example.demohorizontalscrollview;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class HorizontalScrollViewAdapter extends BaseAdapter
{  
    private LayoutInflater mInflater;  
    private List<Map<String, Object>> list;
    public HorizontalScrollViewAdapter(Context context, List<Map<String, Object>> list)  
    {  
        this.list = list;  
        mInflater = LayoutInflater.from(context);    
    }  
    @Override
    public int getCount() {
        // 设配器与list集合大小一致
        return list.size();
    }
    @Override
    public Object getItem(int position) {
        if(list.size()>position){
            return list.get(position);
    }
        return null;
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View v, ViewGroup parent)  
    {   
        Map<String, Object> listData= (Map<String, Object>) getItem(position);          
        Holder viewHolder = null;  
        if (v == null)  
        {       
            viewHolder = new Holder();  
            v = mInflater.inflate(  
                    R.layout.horizontal_sv_item, null);  

            viewHolder.ivTime = (ImageView) v  
                    .findViewById(R.id.iv_time);  

            viewHolder.tvDate = (TextView) v  
            .findViewById(R.id.tv_date);  

            viewHolder.tvTime = (TextView) v  
                    .findViewById(R.id.tv_date_time);           
            v.setTag(viewHolder);  
        } else  
        {  
            viewHolder = (Holder) v.getTag();  
        }  
        if(listData!=null){
            Animation scaleAnimation = new ScaleAnimation(0f, 1.0f,0f,1.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1f);
            AnimationSet set = new AnimationSet(true);  
            set.addAnimation(scaleAnimation);
            set.setDuration(500);
            viewHolder.tvDate.startAnimation(set);
    viewHolder.tvTime.setText(listData.get("title").toString()); 
        }
        return v;  
    }  

    private class Holder  
    {  
        ImageView ivTime;  
        TextView tvDate;  
        TextView tvTime;  
    }  
}  

准备好这些,再Activity中使用

package com.example.demohorizontalscrollview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {
    private DemoHorizontalScrollView mHorizontalScrollView;  
    private HorizontalScrollViewAdapter mAdapter; 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     
        mHorizontalScrollView = (DemoHorizontalScrollView) findViewById(R.id.id_horizontalScrollView);  
        mAdapter = new HorizontalScrollViewAdapter(this, initLeft()); 

        //设置适配器  
        mHorizontalScrollView.initDatas(mAdapter); 
    }

    private List<Map<String, Object>> initLeft(){
        List<Map<String, Object>> list=new ArrayList<Map<String,Object>>();
        Map<String, Object> map=new HashMap<String, Object>();          
            map.put("title", "第一");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第二");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第三");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第四");  
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第五");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第六");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第七");
            list.add(map);

            map=new HashMap<String, Object>();          
            map.put("title", "第八");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第九");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第十");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第十一");  
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第十二");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第十三");
            list.add(map);

            map=new HashMap<String, Object>();
            map.put("title", "第十四");
            list.add(map);
            return list;
    }
}

完成这些就可以运行下效果了;
效果图
虽然在模拟器运行,效果还行吧。
有兴趣的可以一起尝试下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值