HorizontalListView 横向listview

由于优酷的客户端很酷,最近在做视频列表的时候客户要求做出类似效果,开始打算用Gallery的,不过后来发现横向的listview就可以解决这个问题,所以特此记录下,膜拜下国外的大牛,源码的传送门在这里

HorizontalListViewActivity.java

[java]  view plain  copy
  1. package org.com.cctest.listview;  
  2.   
  3.   
  4.   
  5. import org.com.cctest.R;  
  6. import org.com.cctest.adapter.HorizontalListViewAdapter;  
  7.   
  8.   
  9.   
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.view.MotionEvent;  
  13. import android.view.GestureDetector.OnGestureListener;  
  14.   
  15. public class HorizontalListViewActivity extends Activity implements OnGestureListener{  
  16.   
  17.     private HorizontalListViewAdapter hlva;  
  18.     private HorizontalListView hlv;  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.horizontallistview_act);  
  22.         hlv=(HorizontalListView)findViewById(R.id.horizontallistview1);  
  23.         hlva=new HorizontalListViewAdapter(this);  
  24.         hlva.notifyDataSetChanged();  
  25.         hlv.setAdapter(hlva);  
  26.     }  
  27.     private final  String  TAG="HorizontalListViewActivity";  
  28.     @Override  
  29.     public boolean onDown(MotionEvent e) {  
  30.         // TODO Auto-generated method stub  
  31.         return false;  
  32.     }  
  33.   
  34.     @Override  
  35.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  36.             float velocityY) {  
  37.         // TODO Auto-generated method stub  
  38.         return false;  
  39.     }  
  40.   
  41.     @Override  
  42.     public void onLongPress(MotionEvent e) {  
  43.         // TODO Auto-generated method stub  
  44.           
  45.     }  
  46.   
  47.     @Override  
  48.     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,  
  49.             float distanceY) {  
  50.         // TODO Auto-generated method stub  
  51.         return false;  
  52.     }  
  53.   
  54.     @Override  
  55.     public void onShowPress(MotionEvent e) {  
  56.         // TODO Auto-generated method stub  
  57.           
  58.     }  
  59.   
  60.     @Override  
  61.     public boolean onSingleTapUp(MotionEvent e) {  
  62.         // TODO Auto-generated method stub  
  63.         return false;  
  64.     }  
  65.   
  66. }  

horizontallistview_act.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:gravity="center_horizontal"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <org.com.cctest.listview.HorizontalListView  
  9.             android:id="@+id/horizontallistview1"  
  10.             android:layout_width="wrap_content"  
  11.             android:layout_height="fill_parent"  
  12.           />  
  13. </LinearLayout>  

HorizontalListView.java

[java]  view plain  copy
  1. package org.com.cctest.listview;  
  2.   
  3. /* 
  4.  * HorizontalListView.java v1.5 
  5.  * 
  6.  *  
  7.  * The MIT License 
  8.  * Copyright (c) 2011 Paul Soucy (paul@dev-smart.com) 
  9.  *  
  10.  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  11.  * of this software and associated documentation files (the "Software"), to deal 
  12.  * in the Software without restriction, including without limitation the rights 
  13.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  14.  * copies of the Software, and to permit persons to whom the Software is 
  15.  * furnished to do so, subject to the following conditions: 
  16.  *  
  17.  * The above copyright notice and this permission notice shall be included in 
  18.  * all copies or substantial portions of the Software. 
  19.  *  
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  21.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  23.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  24.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  25.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
  26.  * THE SOFTWARE. 
  27.  * 
  28.  */  
  29.   
  30.   
  31. import java.util.LinkedList;  
  32. import java.util.Queue;  
  33.   
  34. import android.content.Context;  
  35. import android.database.DataSetObserver;  
  36. import android.graphics.Rect;  
  37. import android.util.AttributeSet;  
  38. import android.view.GestureDetector;  
  39. import android.view.GestureDetector.OnGestureListener;  
  40. import android.view.MotionEvent;  
  41. import android.view.View;  
  42. import android.widget.AdapterView;  
  43. import android.widget.ListAdapter;  
  44. import android.widget.Scroller;  
  45.   
  46. public class HorizontalListView extends AdapterView<ListAdapter> {  
  47.   
  48.     public boolean mAlwaysOverrideTouch = true;  
  49.     protected ListAdapter mAdapter;  
  50.     private int mLeftViewIndex = -1;  
  51.     private int mRightViewIndex = 0;  
  52.     protected int mCurrentX;  
  53.     protected int mNextX;  
  54.     private int mMaxX = Integer.MAX_VALUE;  
  55.     private int mDisplayOffset = 0;  
  56.     protected Scroller mScroller;  
  57.     private GestureDetector mGesture;  
  58.     private Queue<View> mRemovedViewQueue = new LinkedList<View>();  
  59.     private OnItemSelectedListener mOnItemSelected;  
  60.     private OnItemClickListener mOnItemClicked;  
  61.     private OnItemLongClickListener mOnItemLongClicked;  
  62.     private boolean mDataChanged = false;  
  63.       
  64.   
  65.     public HorizontalListView(Context context, AttributeSet attrs) {  
  66.         super(context, attrs);  
  67.         initView();  
  68.     }  
  69.       
  70.     private synchronized void initView() {  
  71.         mLeftViewIndex = -1;  
  72.         mRightViewIndex = 0;  
  73.         mDisplayOffset = 0;  
  74.         mCurrentX = 0;  
  75.         mNextX = 0;  
  76.         mMaxX = Integer.MAX_VALUE;  
  77.         mScroller = new Scroller(getContext());  
  78.         mGesture = new GestureDetector(getContext(), mOnGesture);  
  79.     }  
  80.       
  81.     @Override  
  82.     public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {  
  83.         mOnItemSelected = listener;  
  84.     }  
  85.       
  86.     @Override  
  87.     public void setOnItemClickListener(AdapterView.OnItemClickListener listener){  
  88.         mOnItemClicked = listener;  
  89.     }  
  90.       
  91.     @Override  
  92.     public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {  
  93.         mOnItemLongClicked = listener;  
  94.     }  
  95.   
  96.     private DataSetObserver mDataObserver = new DataSetObserver() {  
  97.   
  98.         @Override  
  99.         public void onChanged() {  
  100.             synchronized(HorizontalListView.this){  
  101.                 mDataChanged = true;  
  102.             }  
  103.             invalidate();  
  104.             requestLayout();  
  105.         }  
  106.   
  107.         @Override  
  108.         public void onInvalidated() {  
  109.             reset();  
  110.             invalidate();  
  111.             requestLayout();  
  112.         }  
  113.           
  114.     };  
  115.   
  116.     @Override  
  117.     public ListAdapter getAdapter() {  
  118.         return mAdapter;  
  119.     }  
  120.   
  121.     @Override  
  122.     public View getSelectedView() {  
  123.         //TODO: implement  
  124.         return null;  
  125.     }  
  126.   
  127.     @Override  
  128.     public void setAdapter(ListAdapter adapter) {  
  129.         if(mAdapter != null) {  
  130.             mAdapter.unregisterDataSetObserver(mDataObserver);  
  131.         }  
  132.         mAdapter = adapter;  
  133.         mAdapter.registerDataSetObserver(mDataObserver);  
  134.         reset();  
  135.     }  
  136.       
  137.     private synchronized void reset(){  
  138.         initView();  
  139.         removeAllViewsInLayout();  
  140.         requestLayout();  
  141.     }  
  142.   
  143.     @Override  
  144.     public void setSelection(int position) {  
  145.         //TODO: implement  
  146.     }  
  147.       
  148.     private void addAndMeasureChild(final View child, int viewPos) {  
  149.         LayoutParams params = child.getLayoutParams();  
  150.         if(params == null) {  
  151.             params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);  
  152.         }  
  153.   
  154.         addViewInLayout(child, viewPos, params, true);  
  155.         child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),  
  156.                 MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));  
  157.     }  
  158.       
  159.       
  160.   
  161.     @Override  
  162.     protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  163.         super.onLayout(changed, left, top, right, bottom);  
  164.   
  165.         if(mAdapter == null){  
  166.             return;  
  167.         }  
  168.           
  169.         if(mDataChanged){  
  170.             int oldCurrentX = mCurrentX;  
  171.             initView();  
  172.             removeAllViewsInLayout();  
  173.             mNextX = oldCurrentX;  
  174.             mDataChanged = false;  
  175.         }  
  176.   
  177.         if(mScroller.computeScrollOffset()){  
  178.             int scrollx = mScroller.getCurrX();  
  179.             mNextX = scrollx;  
  180.         }  
  181.           
  182.         if(mNextX <= 0){  
  183.             mNextX = 0;  
  184.             mScroller.forceFinished(true);  
  185.         }  
  186.         if(mNextX >= mMaxX) {  
  187.             mNextX = mMaxX;  
  188.             mScroller.forceFinished(true);  
  189.         }  
  190.           
  191.         int dx = mCurrentX - mNextX;  
  192.           
  193.         removeNonVisibleItems(dx);  
  194.         fillList(dx);  
  195.         positionItems(dx);  
  196.           
  197.         mCurrentX = mNextX;  
  198.           
  199.         if(!mScroller.isFinished()){  
  200.             post(new Runnable(){  
  201.                 @Override  
  202.                 public void run() {  
  203.                     requestLayout();  
  204.                 }  
  205.             });  
  206.               
  207.         }  
  208.     }  
  209.       
  210.     private void fillList(final int dx) {  
  211.         int edge = 0;  
  212.         View child = getChildAt(getChildCount()-1);  
  213.         if(child != null) {  
  214.             edge = child.getRight();  
  215.         }  
  216.         fillListRight(edge, dx);  
  217.           
  218.         edge = 0;  
  219.         child = getChildAt(0);  
  220.         if(child != null) {  
  221.             edge = child.getLeft();  
  222.         }  
  223.         fillListLeft(edge, dx);  
  224.           
  225.           
  226.     }  
  227.       
  228.     private void fillListRight(int rightEdge, final int dx) {  
  229.         while(rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) {  
  230.               
  231.             View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this);  
  232.             addAndMeasureChild(child, -1);  
  233.             rightEdge += child.getMeasuredWidth();  
  234.               
  235.             if(mRightViewIndex == mAdapter.getCount()-1) {  
  236.                 mMaxX = mCurrentX + rightEdge - getWidth();  
  237.             }  
  238.               
  239.             if (mMaxX < 0) {  
  240.                 mMaxX = 0;  
  241.             }  
  242.             mRightViewIndex++;  
  243.         }  
  244.           
  245.     }  
  246.       
  247.     private void fillListLeft(int leftEdge, final int dx) {  
  248.         while(leftEdge + dx > 0 && mLeftViewIndex >= 0) {  
  249.             View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this);  
  250.             addAndMeasureChild(child, 0);  
  251.             leftEdge -= child.getMeasuredWidth();  
  252.             mLeftViewIndex--;  
  253.             mDisplayOffset -= child.getMeasuredWidth();  
  254.         }  
  255.     }  
  256.       
  257.     private void removeNonVisibleItems(final int dx) {  
  258.         View child = getChildAt(0);  
  259.         while(child != null && child.getRight() + dx <= 0) {  
  260.             mDisplayOffset += child.getMeasuredWidth();  
  261.             mRemovedViewQueue.offer(child);  
  262.             removeViewInLayout(child);  
  263.             mLeftViewIndex++;  
  264.             child = getChildAt(0);  
  265.               
  266.         }  
  267.           
  268.         child = getChildAt(getChildCount()-1);  
  269.         while(child != null && child.getLeft() + dx >= getWidth()) {  
  270.             mRemovedViewQueue.offer(child);  
  271.             removeViewInLayout(child);  
  272.             mRightViewIndex--;  
  273.             child = getChildAt(getChildCount()-1);  
  274.         }  
  275.     }  
  276.       
  277.     private void positionItems(final int dx) {  
  278.         if(getChildCount() > 0){  
  279.             mDisplayOffset += dx;  
  280.             int left = mDisplayOffset;  
  281.             for(int i=0;i<getChildCount();i++){  
  282.                 View child = getChildAt(i);  
  283.                 int childWidth = child.getMeasuredWidth();  
  284.                 child.layout(left, 0, left + childWidth, child.getMeasuredHeight());  
  285.                 left += childWidth + child.getPaddingRight();  
  286.             }  
  287.         }  
  288.     }  
  289.       
  290.     public synchronized void scrollTo(int x) {  
  291.         mScroller.startScroll(mNextX, 0, x - mNextX, 0);  
  292.         requestLayout();  
  293.     }  
  294.       
  295.     @Override  
  296.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  297.         boolean handled = super.dispatchTouchEvent(ev);  
  298.         handled |= mGesture.onTouchEvent(ev);  
  299.         return handled;  
  300.     }  
  301.       
  302.     protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  303.                 float velocityY) {  
  304.         synchronized(HorizontalListView.this){  
  305.             mScroller.fling(mNextX, 0, (int)-velocityX, 00, mMaxX, 00);  
  306.         }  
  307.         requestLayout();  
  308.           
  309.         return true;  
  310.     }  
  311.       
  312.     protected boolean onDown(MotionEvent e) {  
  313.         mScroller.forceFinished(true);  
  314.         return true;  
  315.     }  
  316.       
  317.     private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {  
  318.   
  319.         @Override  
  320.         public boolean onDown(MotionEvent e) {  
  321.             return HorizontalListView.this.onDown(e);  
  322.         }  
  323.   
  324.         @Override  
  325.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  326.                 float velocityY) {  
  327.             return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY);  
  328.         }  
  329.   
  330.         @Override  
  331.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  332.                 float distanceX, float distanceY) {  
  333.               
  334.             synchronized(HorizontalListView.this){  
  335.                 mNextX += (int)distanceX;  
  336.             }  
  337.             requestLayout();  
  338.               
  339.             return true;  
  340.         }  
  341.   
  342.         @Override  
  343.         public boolean onSingleTapConfirmed(MotionEvent e) {  
  344.             for(int i=0;i<getChildCount();i++){  
  345.                 View child = getChildAt(i);  
  346.                 if (isEventWithinView(e, child)) {  
  347.                     if(mOnItemClicked != null){  
  348.                         mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId( mLeftViewIndex + 1 + i ));  
  349.                     }  
  350.                     if(mOnItemSelected != null){  
  351.                         mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId( mLeftViewIndex + 1 + i ));  
  352.                     }  
  353.                     break;  
  354.                 }  
  355.                   
  356.             }  
  357.             return true;  
  358.         }  
  359.           
  360.         @Override  
  361.         public void onLongPress(MotionEvent e) {  
  362.             int childCount = getChildCount();  
  363.             for (int i = 0; i < childCount; i++) {  
  364.                 View child = getChildAt(i);  
  365.                 if (isEventWithinView(e, child)) {  
  366.                     if (mOnItemLongClicked != null) {  
  367.                         mOnItemLongClicked.onItemLongClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i));  
  368.                     }  
  369.                     break;  
  370.                 }  
  371.   
  372.             }  
  373.         }  
  374.   
  375.         private boolean isEventWithinView(MotionEvent e, View child) {  
  376.             Rect viewRect = new Rect();  
  377.             int[] childPosition = new int[2];  
  378.             child.getLocationOnScreen(childPosition);  
  379.             int left = childPosition[0];  
  380.             int right = left + child.getWidth();  
  381.             int top = childPosition[1];  
  382.             int bottom = top + child.getHeight();  
  383.             viewRect.set(left, top, right, bottom);  
  384.             return viewRect.contains((int) e.getRawX(), (int) e.getRawY());  
  385.         }  
  386.     };  
  387.   
  388.       
  389.   
  390. }  
HorizontalListViewAdapter.java

[java]  view plain  copy
  1. package org.com.cctest.adapter;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.com.cctest.R;  
  7. import org.com.cctest.bean.VideoBean;  
  8. import android.content.Context;  
  9. import android.view.LayoutInflater;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.widget.BaseAdapter;  
  13. import android.widget.ImageView;  
  14. import android.widget.TextView;  
  15.   
  16. public class HorizontalListViewAdapter extends BaseAdapter{  
  17.   
  18.     public HorizontalListViewAdapter(Context con){  
  19.         mInflater=LayoutInflater.from(con);  
  20.     }  
  21.     @Override  
  22.     public int getCount() {  
  23.         return 5;  
  24.     }  
  25.     private LayoutInflater mInflater;  
  26.     @Override  
  27.     public Object getItem(int position) {  
  28.         return position;  
  29.     }  
  30.     private ViewHolder vh    =new ViewHolder();  
  31.     private static class ViewHolder {  
  32.         private TextView time ;  
  33.         private TextView title ;  
  34.         private ImageView im;  
  35.     }  
  36.     @Override  
  37.     public long getItemId(int position) {  
  38.         return position;  
  39.     }  
  40.   
  41.     @Override  
  42.     public View getView(int position, View convertView, ViewGroup parent) {  
  43.         if(convertView==null){  
  44.             convertView = mInflater.inflate(R.layout.horizontallistview_item, null);  
  45.             vh.im=(ImageView)convertView.findViewById(R.id.iv_pic);  
  46.             vh.time=(TextView)convertView.findViewById(R.id.tv_time);  
  47.             vh.title=(TextView)convertView.findViewById(R.id.tv_name);  
  48.             convertView.setTag(vh);  
  49.         }else{  
  50.             vh=(ViewHolder)convertView.getTag();  
  51.         }  
  52.         vh.time.setText("00:00");  
  53.         vh.title.setText("XXXXXX");  
  54.         return convertView;  
  55.     }  
  56. }  

horizontallistview_item.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/rl"  
  4.     android:layout_width="150dip"  
  5.     android:layout_height="100dip"  
  6.     android:background="@color/writebg" >  
  7.   
  8.     <!-- android:src="@drawable/test1"android:scaleType="centerCrop" -->  
  9.   
  10.     <ImageView  
  11.         android:id="@+id/iv_pic"  
  12.         android:layout_width="140dip"  
  13.         android:layout_height="100dip"  
  14.         android:paddingBottom="5dip"  
  15.         android:paddingLeft="10dip"  
  16.         android:paddingRight="10dip"  
  17.         android:paddingTop="10dip"  
  18.         android:scaleType="fitXY"  
  19.         android:src="@drawable/test5"  
  20.         />  
  21.     <!-- android:scaleType="fitXY" -->  
  22.   
  23.     <TextView  
  24.         android:id="@+id/tv_time"  
  25.         android:layout_width="120dip"  
  26.         android:layout_height="wrap_content"  
  27.         android:layout_alignBottom="@+id/iv_pic"  
  28.         android:layout_marginBottom="6dip"  
  29.         android:layout_marginLeft="10dip"  
  30.         android:background="#88252525"  
  31.         android:ellipsize="end"  
  32.         android:paddingLeft="5dip"  
  33.         android:singleLine="true"  
  34.         android:text="12:10"  
  35.         android:textColor="#FFF"  
  36.         android:textSize="10sp" />  
  37.   
  38.     <TextView  
  39.         android:id="@+id/tv_name"  
  40.         android:layout_width="wrap_content"  
  41.         android:layout_height="wrap_content"  
  42.         android:layout_below="@+id/tv_time"  
  43.         android:ellipsize="end"  
  44.         android:maxLength="10"  
  45.         android:paddingLeft="12dip"  
  46.         android:paddingRight="5dip"  
  47.         android:singleLine="true"  
  48.         android:text="XXXXXXXXX"  
  49.         android:textColor="@color/black"  
  50.         android:textSize="11sp" />  
  51.   
  52. </RelativeLayout>  
源码下载地址:http://download.csdn.net/detail/chen88358323/4823542
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值