




已阅读5页,还剩31页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android横向ListView在日常开发中经常会发现横向的ListView。下面讨论实现方案。 1.动态的添加布局。RelativeLayout view = (RelativeLayout) LayoutInflater.from(this) .inflate(R.layout.demo, null);ListView.addView(view);2.通过继承AdapterView(ListAdapter)自定义类实现 部分关键代码如下: 类名:HorizontalListView(这个类不是我实现的,我只是拿来用)布局代码代码粘贴如下:package com.homelink.newlink.view;import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.content.Context;import android.content.res.TypedArray;import android.database.DataSetObserver;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.os.Build;import android.os.Bundle;import android.os.Parcelable;import android.support.v4.view.ViewCompat;import android.support.v4.widget.EdgeEffectCompat;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.HapticFeedbackConstants;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.ScrollView;import android.widget.Scroller;import com.homelink.newlink.R;import mon.utils.device.DensityUtil;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import java.util.Queue;/* * Created by jou on 2017/1/4. */public class HorizontalListView extends AdapterView /* * Defines where to insert items into the ViewGroup, as defined in code ViewGroup * #addViewInLayout(View, int, LayoutParams, boolean) */ private static final int INSERT_AT_END_OF_LIST = -1; private static final int INSERT_AT_START_OF_LIST = 0; /* The velocity to use for overscroll absorption */ private static final float FLING_DEFAULT_ABSORB_VELOCITY = 30f; /* The friction amount to use for the fling tracker */ private static final float FLING_FRICTION = 0.009f; /* * Used for tracking the state data necessary to restore the HorizontalListView to its previous * state after a rotation occurs */ private static final String BUNDLE_ID_CURRENT_X = BUNDLE_ID_CURRENT_X; /* * The bundle id of the parents state. Used to restore the parents state after a rotation * occurs */ private static final String BUNDLE_ID_PARENT_STATE = BUNDLE_ID_PARENT_STATE; /* Tracks ongoing flings */ protected Scroller mFlingTracker = new Scroller(getContext(); /* Gesture listener to receive callbacks when gestures are detected */ private final GestureListener mGestureListener = new GestureListener(); /* Used for detecting gestures within this view so they can be handled */ private GestureDetector mGestureDetector; /* This tracks the starting layout position of the leftmost view */ private int mDisplayOffset; /* Holds a reference to the adapter bound to this view */ protected ListAdapter mAdapter; /* Holds a cache of recycled views to be reused as needed */ private ListQueue mRemovedViewsCache = new ArrayListQueue(); /* Flag used to mark when the adapters data has changed, so the view can be relaid out */ private boolean mDataChanged = false; /* Temporary rectangle to be used for measurements */ private Rect mRect = new Rect(); /* Tracks the currently touched view, used to delegate touches to the view being touched */ private View mViewBeingTouched = null; /* The width of the divider that will be used between list items */ private int mDividerWidth = 0; /* The drawable that will be used as the list divider */ private Drawable mDivider = null; /* The x position of the currently rendered view */ protected int mCurrentX; /* The x position of the next to be rendered view */ protected int mNextX; /* Used to hold the scroll position to restore to post rotate */ private Integer mRestoreX = null; /* * Tracks the maximum possible X position, stays at max value until last item is laid out and it * can be determined */ private int mMaxX = Integer.MAX_VALUE; /* The adapter index of the leftmost view currently visible */ private int mLeftViewAdapterIndex; /* The adapter index of the rightmost view currently visible */ private int mRightViewAdapterIndex; /* This tracks the currently selected accessibility item */ private int mCurrentlySelectedAdapterIndex; /* * Callback interface to notify listener that the user has scrolled this view to the point that * it is low on data. */ private RunningOutOfDataListener mRunningOutOfDataListener = null; /* * This tracks the user value set of how many items from the end will be considered running out * of data. */ private int mRunningOutOfDataThreshold = 0; /* * Tracks if we have told the listener that we are running low on data. We only want to tell * them once. */ private boolean mHasNotifiedRunningLowOnData = false; /* * Callback interface to be invoked when the scroll state has changed. */ private OnScrollStateChangedListener mOnScrollStateChangedListener = null; /* * Represents the current scroll state of this view. Needed so we can detect when the state * changes so scroll listener can be notified. */ private OnScrollStateChangedListener.ScrollState mCurrentScrollState = OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE; /* * Tracks the state of the left edge glow. */ private EdgeEffectCompat mEdgeGlowLeft; /* * Tracks the state of the right edge glow. */ private EdgeEffectCompat mEdgeGlowRight; /* The height measure spec for this view, used to help size children views */ private int mHeightMeasureSpec; /* Used to track if a view touch should be blocked because it stopped a fling */ private boolean mBlockTouchAction = false; /* * Used to track if the parent vertically scrollable view has been told to * DisallowInterceptTouchEvent */ private boolean mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent = false; /* * The listener that receives notifications when this view is clicked. */ private OnClickListener mOnClickListener; /* * Recode the position of press and loose */ private MotionEvent mPressEvent; private MotionEvent mLooseEvent; /* * MaoDian mode */ private boolean mIsAnchorEnable; /* * Filing mode */ private boolean mIsFilingEnable = true; public HorizontalListView(Context context, AttributeSet attrs) super(context, attrs); mEdgeGlowLeft = new EdgeEffectCompat(context); mEdgeGlowRight = new EdgeEffectCompat(context); mGestureDetector = new GestureDetector(context, mGestureListener); bindGestureDetector(); initView(); retrieveXmlConfiguration(context, attrs); setWillNotDraw(false); / If the OS version is high enough then set the friction on the fling tracker */ if (Build.VERSION.SDK_INT = Build.VERSION_CODES.HONEYCOMB) HoneycombPlus.setFriction(mFlingTracker, FLING_FRICTION); /* Registers the gesture detector to receive gesture notifications for this view */ private void bindGestureDetector() / Generic touch listener that can be applied to any view that needs to process gestures final OnTouchListener gestureListenerHandler = new OnTouchListener() Override public boolean onTouch(final View v, final MotionEvent event) / Delegate the touch event to our gesture detector return mGestureDetector.onTouchEvent(event); ; setOnTouchListener(gestureListenerHandler); /* * When this HorizontalListView is embedded within a vertical scrolling view it is important to * disable the parent view from interacting with * any touch events while the user is scrolling within this HorizontalListView. This will start * at this view and go up the view tree looking * for a vertical scrolling view. If one is found it will enable or disable parent touch * interception. * * param disallowIntercept If true the parent will be prevented from intercepting child touch * events */ private void requestParentListViewToNotInterceptTouchEvents(Boolean disallowIntercept) / Prevent calling this more than once needlessly if (mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent != disallowIntercept) View view = this; while (view.getParent() instanceof View) / If the parent is a ListView or ScrollView then disallow intercepting of touch events if (view.getParent() instanceof ListView | view.getParent() instanceof ScrollView) view.getParent().requestDisallowInterceptTouchEvent(disallowIntercept); mIsParentVerticiallyScrollableViewDisallowingInterceptTouchEvent = disallowIntercept; return; view = (View) view.getParent(); /* * Parse the XML configuration for this widget * * param context Context used for extracting attributes * param attrs The Attribute Set containing the ColumnView attributes */ private void retrieveXmlConfiguration(Context context, AttributeSet attrs) if (attrs != null) TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HorizontalListView); / Get the provided drawable from the XML final Drawable d = a.getDrawable(R.styleable.HorizontalListView_android_divider); if (d != null) / If a drawable is provided to use as the divider then use its intrinsic width for the divider width setDivider(d); / If a width is explicitly specified then use that width final int dividerWidth = a.getDimensionPixelSize(R.styleable.HorizontalListView_dividerWidth, 0); if (dividerWidth != 0) setDividerWidth(dividerWidth); a.recycle(); Override public Parcelable onSaveInstanceState() Bundle bundle = new Bundle(); / Add the parent state to the bundle bundle.putParcelable(BUNDLE_ID_PARENT_STATE, super.onSaveInstanceState(); / Add our state to the bundle bundle.putInt(BUNDLE_ID_CURRENT_X, mCurrentX); return bundle; Override public void onRestoreInstanceState(Parcelable state) if (state instanceof Bundle) Bundle bundle = (Bundle) state; / Restore our state from the bundle mRestoreX = Integer.valueOf(bundle.getInt(BUNDLE_ID_CURRENT_X); / Restore out parents state from the bundle super.onRestoreInstanceState(bundle.getParcelable(BUNDLE_ID_PARENT_STATE); /* * Sets the drawable that will be drawn between each item in the list. If the drawable does * not have an intrinsic width, you should also call link #setDividerWidth(int) * * param divider The drawable to use. */ public void setDivider(Drawable divider) mDivider = divider; if (divider != null) setDividerWidth(divider.getIntrinsicWidth(); else setDividerWidth(0); /* * Sets the width of the divider that will be drawn between each item in the list. Calling * this will override the intrinsic width as set by link #setDivider(android.graphics.drawable.Drawable) * * param width The width of the divider in pixels. */ public void setDividerWidth(int width) mDividerWidth = width; / Force the view to rerender itself requestLayout(); invalidate(); private void initView() mLeftViewAdapterIndex = -1; mRightViewAdapterIndex = -1; mDisplayOffset = 0; mCurrentX = 0; mNextX = 0; mMaxX = Integer.MAX_VALUE; setCurrentScrollState(OnScrollStateChangedListener.ScrollState.SCROLL_STATE_IDLE); /* * Will re-initialize the HorizontalListView to remove all child views rendered and reset to * initial configuration. */ private void reset() initView(); removeAllViewsInLayout(); requestLayout(); /* DataSetObserver used to capture adapter data change events */ private DataSetObserver mAdapterDataObserver = new DataSetObserver() Override public void onChanged() mDataChanged = true; / Clear so we can notify again as we run out of data mHasNotifiedRunningLowOnData = false; unpressTouchedChild(); / Invalidate and request layout to force this view to completely redraw itself invalidate(); requestLayout(); Override public void onInvalidated() / Clear so we can notify again as we run out of data mHasNotifiedRunningLowOnData = false; unpressTouchedChild(); reset(); / Invalidate and request layout to force this view to completely redraw itself invalidate(); requestLayout(); ; Override public void setSelection(int position) mCurrentlySelectedAdapterIndex = position; Override public View getSelectedView() return getChild(mCurrentlySelectedAdapterIndex); Override public void setAdapter(ListAdapter adapter) if (mAdapter != null) mAdapter.unregisterDataSetObserver(mAdapterDataObserver); if (adapter != null) / Clear so we can notify again as we run out of data mHasNotifiedRunningLowOnData = false; mAdapter = adapter; mAdapter.registerDataSetObserver(mAdapterDataObserver); initializeRecycledViewCache(mAdapter.getViewTypeCount(); reset(); Override public ListAdapter getAdapter() return mAdapter; /* * Will create and initialize a cache for the given number of different types of views. * * param viewTypeCount - The total number of different views supported */ private void initializeRecycledViewCache(int viewTypeCount) / The cache is created such that the response from mAdapter.getItemViewType is the array index to the correct cache for that item. mRemovedViewsCache.clear(); for (int i = 0; i viewTypeCount; i+) mRemovedViewsCache.add(new LinkedList(); /* * Returns a recycled view from the cache that can be reused, or null if one is not available. */ private View getRecycledView(int adapterIndex) int itemViewType = mAdapter.getItemViewType(adapterIndex); if (isItemViewTypeValid(itemViewType) return mRemovedViewsCache.get(itemViewType).poll(); return null; /* * Adds the provided view to a recycled views cache. */ private void recycleView(int adapterIndex, View view) / There is one Queue of views for each different type of view. / Just add the view to the pile of other views of the same type. / The order they are added and removed does not matter. int itemViewType = mAdapter.getItemViewType(adapterIndex); if (isItemViewTypeValid(itemViewType) mRemovedViewsCache.get(itemViewType).offer(view); private boolean isItemViewTypeValid(int itemViewType) return itemViewType 0) childWidthSpec = MeasureSpec.makeMeasureSpec(childLayoutParams.width, MeasureSpec.EXACTLY); else childWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); child.measure(childWidthSpec, childHeightSpec); /* Gets a childs layout parameters, defaults if not available. */ private LayoutParams getLayoutParams(View child) LayoutParams layoutParams = child.getLayoutParams(); if (layoutParams = null) / Since this is a horizontal list view default to matching the parents height, and wrapping the width layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); return layoutParams; SuppressLint(WrongCall) Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) super.onLayout(changed, left, top, right, bottom); if (mAdapter = null) return; / Force the OS to redraw this view invalidate(); / If the data changed then reset everything and render from scratch at the same offset as
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 农林牧渔业金融服务创新创业项目商业计划书
- 急诊科群体中毒应急预案演练脚本(2篇)
- 2025年 七年级上册语文第一单元测试卷含答案
- 黑龙江省齐齐哈尔市九校2025-2026学年高三上学期期初联考政治试题(含答案)
- 陕西省汉中市2026届高三上学期第一次校际联考生物试卷(含答案)
- cors基站管理办法
- 装修预审管理办法规定
- 《内部讲师管理办法》
- 互联网药店门店员工劳动合同及电商服务合同
- 生态修复项目资金封闭管理及生态效益评估协议
- 2025年德惠市公开招聘社区工作者(194人)备考练习题库及答案解析
- 三同时培训课件
- 2025国家网络安全宣传周
- 单位与个人劳务合同范本
- 2025至2030中国中医馆行业市场发展分析及前景趋势与投资机会报告
- 甘肃陇西村文书考试题及答案
- 2025年联合运营合作伙伴合同模板
- 美团骑手2025年度劳动合同范本下载
- 2024-2025学年云南省楚雄州统编版四年级下册期末考试语文试卷
- 贵州省黔南州2024-2025学年八年级下学期期末道德与法治试题(含答案)
- 2025-2026学年湘美版(2024)初中美术七年级上册教学计划及进度表
评论
0/150
提交评论