自定义类似Gridview 不同行列数不同 的显示控件
2015-08-26 10:34
507 查看
显示不同行不同列的数据,使用的适配器必须与 自己的显示控件对应,适配器也需要重新定义,
控件如下
可以根据不同需求,进行修改
与之对应的适配器代码如下
新人,有问题请各位大神在下面指出来,谢谢
控件如下
import java.util.LinkedList; import java.util.Queue; import android.annotation.SuppressLint; import android.content.Context; import android.database.DataSetObserver; import android.graphics.Rect; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.GestureDetector.OnGestureListener; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.Scroller; /** * 候选词与符号显示控件 * 不同行不同列 * @author q * */ public class GridDCView extends AdapterView<ListAdapter> { protected ListAdapter mAdapter; private int mTopViewIndex = -1; private int mBottomViewIndex = 0; protected int mCurrentY; protected int mNextY; private int mMaxY = Integer.MAX_VALUE; private int mDisplayOffset = 0; protected Scroller mScroller; private GestureDetector mGesture; private Queue<View> mRemovedViewQueue = new LinkedList<View>(); private OnItemClickListener mOnItemClicked = null; private boolean mIsSetAD = false; /** * 数据是否发生了变化 */ private boolean mDataChanged = false; private boolean mBlockTouchAction = false; private Rect mRect = new Rect(); private View mViewBeingTouched = null; private boolean isScroll = false; private float mYposition = 0; public GridDCView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; initView(); setWillNotDraw(false); } private synchronized void initView() { mTopViewIndex = -1; mBottomViewIndex = 0; mDisplayOffset = 0; mCurrentY = 0; mNextY = 0; mMaxY = Integer.MAX_VALUE; if(mScroller== null){ mScroller = new Scroller(getContext()); } if(mGesture== null){ mGesture = new GestureDetector(getContext(), mOnGesture); } } @Override public void setOnItemClickListener(AdapterView.OnItemClickListener listener){ mOnItemClicked = listener; } private DataSetObserver mDataObserver = new DataSetObserver() { @SuppressLint("WrongCall") @Override public void onChanged(){ //log.l("73 onChanged "); if(mIsSetAD){ mIsSetAD = false; }else{ synchronized(GridDCView.this){ mDataChanged = true; } mTopViewIndex = -1; mBottomViewIndex = 0; mDisplayOffset = 0; mCurrentY = 0; mNextY = 0; mMaxY = Integer.MAX_VALUE; onLayout(false, 0, 0, getWidth(), getHeight()); } } @Override public void onInvalidated() { } }; @Override public ListAdapter getAdapter() { return mAdapter; } @Override public View getSelectedView() { return null; } @Override public void setAdapter(ListAdapter adapter) { if(mAdapter != null) { mAdapter.unregisterDataSetObserver(mDataObserver); } mIsSetAD = true; mAdapter = adapter; mAdapter.registerDataSetObserver(mDataObserver); reset(); } private synchronized void reset(){ initView(); removeAllViewsInLayout(); requestLayout(); } @Override public void setSelection(int position) { } private void addAndMeasureChild(final View child, int viewPos) { LayoutParams params = child.getLayoutParams(); if(params == null) { params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } addViewInLayout(child, viewPos, params, true); child.setMinimumWidth(params.width); child.setMinimumHeight(params.height); child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); } @SuppressLint("DrawAllocation") @Override protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) { if(mAdapter == null){ return; } if(mDataChanged){ removeAllView(); mDataChanged = false; mScroller.forceFinished(true); fillListBottom(0,0); if(getChildCount() > 0){ int tops = 0; for(int i=0;i<getChildCount();i++){ View child = getChildAt(i); int childHight = child.getMeasuredHeight(); int position = ((GridDCViewAdapter.ViewHolder)child.getTag()).position; int linecount = ((GridDCViewAdapter.ViewHolder)child.getTag()).linecount; if( position !=0 ){ int x = (position-1)*(getWidth()/linecount); child.layout(x,tops,child.getMeasuredWidth(),tops + childHight); }else{ int x = (position-1)*(getWidth()/linecount); child.layout(x,tops,child.getMeasuredWidth(),tops + childHight); tops += childHight + child.getPaddingBottom(); } } } invalidate(); }else{ if(mScroller.computeScrollOffset()){ int scrolly = mScroller.getCurrY(); mNextY = scrolly; } if(mNextY <= 0){ mNextY = 0; mScroller.forceFinished(true); } if(mNextY >= mMaxY) { mNextY = mMaxY; mScroller.forceFinished(true); } int dy = mCurrentY - mNextY; removeNonVisibleItems(dy); fillList(dy); positionItems(dy); mCurrentY = mNextY; if(!mScroller.isFinished()){ post(new Runnable(){ @SuppressLint("WrongCall") @Override public void run() { onLayout(false, 0, 0, getWidth(), getHeight()); } }); } } } private void fillList(final int dx) { int edge = 0; View child = getChildAt(getChildCount()-1); if(child != null) { edge = child.getBottom(); } fillListBottom(edge, dx); edge = 0; child = getChildAt(0); if(child != null) { edge = child.getTop(); } fillListTop(edge, dx); } private void fillListBottom(int bottomEdge, final int dx) { while(bottomEdge + dx < getHeight() && mBottomViewIndex < mAdapter.getCount()) { View child = mAdapter.getView(mBottomViewIndex,mRemovedViewQueue.poll(), this); addAndMeasureChild(child, -1); int position = ((GridDCViewAdapter.ViewHolder)child.getTag()).position; if( position == ((GridDCViewAdapter.ViewHolder)child.getTag()).linecount ){ bottomEdge += child.getMeasuredHeight()/*+child.getPaddingTop()+child.getPaddingBottom()*/; } if(mBottomViewIndex == mAdapter.getCount()-1) { mMaxY = mCurrentY + bottomEdge - getHeight(); } if (mMaxY < 0) { mMaxY = 0; } mBottomViewIndex++; } } private void fillListTop(int topEdge, final int dx) { while(topEdge + dx > 0 && mTopViewIndex >= 0) { View child = mAdapter.getView(mTopViewIndex, mRemovedViewQueue.poll(), this); addAndMeasureChild(child, 0); int position = ((GridDCViewAdapter.ViewHolder)child.getTag()).position; if( position == 1 ){ topEdge -= child.getMeasuredHeight(); mDisplayOffset -= child.getMeasuredHeight(); } mTopViewIndex--; } } /** * 删除不可见控件 * @param dx */ private void removeNonVisibleItems(final int dy) { View child = getChildAt(0); while(child != null && child.getBottom() + dy <= 0) { if(((GridDCViewAdapter.ViewHolder)child.getTag()).position==((GridDCViewAdapter.ViewHolder)child.getTag()).linecount){ mDisplayOffset += child.getMeasuredHeight(); } mRemovedViewQueue.offer(child); removeViewInLayout(child); mTopViewIndex++; child = getChildAt(0); } child = getChildAt(getChildCount()-1); while(child != null && child.getTop() + dy >= getHeight()) { mRemovedViewQueue.offer(child); removeViewInLayout(child); mBottomViewIndex--; child = getChildAt(getChildCount()-1); } } private void positionItems(final int dy) { if(getChildCount() > 0){ mDisplayOffset += dy; int top = mDisplayOffset; int left = 0; for(int i=0;i<getChildCount();i++){ View child = getChildAt(i); int childHight = child.getMeasuredHeight(); int with = child.getMeasuredWidth(); int position = ((GridDCViewAdapter.ViewHolder)child.getTag()).position; int linecount = ((GridDCViewAdapter.ViewHolder)child.getTag()).linecount; left +=child.getPaddingLeft(); if( position != linecount ){ child.layout( left,top,left+with,top + childHight); left +=(with+child.getPaddingRight()); }else{ child.layout( left,top,left+with,top + childHight); top += childHight + child.getPaddingBottom(); left = 0; } } } } @SuppressLint("WrongCall") public synchronized void scrollTo(int y) { mScroller.startScroll(0, mNextY, 0,y - mNextY); onLayout(false, 0, 0, getWidth(), getHeight()); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_UP ){ if(!isScroll){ for(int i=0;i<getChildCount();i++){ View child = getChildAt(i); if (isEventWithinView(ev, child)) { if(mOnItemClicked != null){ playSV(); mOnItemClicked.onItemClick(GridDCView.this, child, mTopViewIndex + 1 + i, mAdapter.getItemId( mTopViewIndex + 1 + i )); unpressTouchedChild(); return true; } break; } } } unpressTouchedChild(); }else if(ev.getAction() == MotionEvent.ACTION_DOWN){ for(int i=0;i<getChildCount();i++){ View child = getChildAt(i); if (isEventWithinView(ev, child)) { child.setPressed(true); break; } } } boolean handled = super.dispatchTouchEvent(ev); handled |= mGesture.onTouchEvent(ev); return handled; } @SuppressLint("WrongCall") protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { synchronized(GridDCView.this){ mScroller.fling(0,mNextY,0,(int)-velocityY, 0, 0, 0, mMaxY); } onLayout(false, 0, 0, getWidth(), getHeight()); return true; } protected boolean onDown(MotionEvent e) { isScroll = false; mYposition = e.getY(); mBlockTouchAction = !mScroller.isFinished(); mScroller.forceFinished(true); unpressTouchedChild(); if (!mBlockTouchAction) { final int index = getChildIndex((int) e.getX(), (int) e.getY()); if (index >= 0) { mViewBeingTouched = getChildAt(index); if (mViewBeingTouched != null) { mViewBeingTouched.setPressed(true); refreshDrawableState(); } } } return true; } private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { return GridDCView.this.onDown(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return GridDCView.this.onFling(e1, e2, velocityX, velocityY); } @SuppressLint("WrongCall") @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { unpressAllChild(); if(Math.abs(e2.getY()-mYposition)>15){ isScroll = true; } synchronized(GridDCView.this){ mNextY += (int)distanceY; } onLayout(false, 0, 0, getWidth(), getHeight()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { unpressTouchedChild(); return true; } }; private boolean isEventWithinView(MotionEvent e, View child) { int x = (int) e.getX(); int y = (int) e.getY(); child.getHitRect(mRect); if (mRect.contains(x, y)) { return true; } return false; } private int getChildIndex(final int x, final int y) { int childCount = getChildCount(); for (int index = 0; index < childCount; index++) { getChildAt(index).getHitRect(mRect); if (mRect.contains(x, y)) { return index; } } return -1; } private void unpressTouchedChild() { if (mViewBeingTouched != null) { mViewBeingTouched.setPressed(false); refreshDrawableState(); mViewBeingTouched = null; } } private void unpressAllChild(){ for(int i = 0 ; i < getChildCount();i++){ View child = getChildAt(i); child.setPressed(false); } } @SuppressLint("WrongCall") public void toStartPosition(){ mTopViewIndex = -1; mBottomViewIndex = 0; mDisplayOffset = 0; mCurrentY = 0; mNextY = 0; mMaxY = Integer.MAX_VALUE; onLayout(false, 0, 0, getWidth(), getHeight()); } @SuppressLint("WrongCall") public void refreshShow(){ synchronized(GridDCView.this){ mDataChanged = true; } mTopViewIndex = -1; mBottomViewIndex = 0; mDisplayOffset = 0; mCurrentY = 0; mNextY = 0; mMaxY = Integer.MAX_VALUE; onLayout(false, 0, 0, getWidth(), getHeight()); } private void removeAllView(){ View child = null; int count = getChildCount(); for(int i=0;i<count;i++){ child = getChildAt(i); mRemovedViewQueue.offer(child); } removeAllViewsInLayout(); } @SuppressLint("WrongCall") public void pageDown(){ mNextY+=getHeight(); onLayout(false, 0, 0, getWidth(), getHeight()); } @SuppressLint("WrongCall") public void pageUp(){ if(mNextY>getHeight()){ mNextY-=getHeight(); }else{ mNextY = 0; } onLayout(false, 0, 0, getWidth(), getHeight()); } public boolean isHaveItemClickListener(){ if( mOnItemClicked == null){ return false; } return true; } public void clearCacheView(){ mRemovedViewQueue.clear(); } }
可以根据不同需求,进行修改
与之对应的适配器代码如下
import java.util.TreeMap; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.TextView; public class GridDCViewAdapter extends SymbolBaseAdapter{ private static final String TAG = "TAG"; private String[]data = null; /** * 键 数据位置, 值 该行数量 */ private TreeMap< Integer, Integer> lineCountMap = new TreeMap<>(); /** * 键 数据位置, 值 在该行位置 */ private TreeMap< Integer, Integer> columnPositionMap = new TreeMap<>(); private int mViewWith = 0; private GridDCView mGDCView = null; private Context mService = null; private int mCount = 0; private int mSymSize = 0; /** * @param data 显示数据 * @param context * @param view 显示控件 * @param service */ public GridDCViewAdapter(String[] data, GridDCView view,<span style="font-family: Arial, Helvetica, sans-serif;">Context </span><span style="font-family: Arial, Helvetica, sans-serif;">service) {</span> super(); this.data = data; if(data == null){ mCount = 0; }else{ mCount = this.data.length; } this.mGDCView = view; mService = service; } @Override public int getCount() { if(data == null){ return 0; } return mCount; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder ; if(convertView == null){ TextView itemView = new TextView(mService); itemView.setClickable(false); convertView = itemView; viewHolder = new ViewHolder(); convertView.setTag(viewHolder); convertView.setPadding(1, 2, 1, 2); ((TextView)convertView).setGravity(Gravity.CENTER); }else{ viewHolder=(ViewHolder)convertView.getTag(); } if(mViewWith != mGDCView.getWidth()){ mViewWith = mGDCView.getWidth(); } if(lineCountMap.get(position) == null){ int num = num(position); for( int i = 0;i < num;i++){ lineCountMap.put(position+i, num); columnPositionMap.put(position+i, i+1); } } viewHolder.linecount = lineCountMap.get(position); viewHolder.position = columnPositionMap.get(position); ((TextView)convertView).setText(data[position]); ((TextView)convertView).setLayoutParams(new LayoutParams(mViewWith/viewHolder.linecount-2, mService.mStandHight)); return convertView; } /** * 获取该行显示数量 * @param position * @return */ private int num(int position){ int size = <span style="font-family: Arial, Helvetica, sans-serif;">3</span>; if(position+1 > mCount){ Log.e(TAG, "数组越界"); return 0; } if(data[position].length() < size){//3 if(position+2 > mCount){ return 1; } if(data[position+1].length() < size){//3 if(position+3 > mCount||position+4 > mCount){ return 2; } if(data[position+2].length() < size&&data[position+3].length() < size/*&&data[startposition+4].length() < 3*/){//3 return 4; }else{ return 2; } }else if(data[position+1].length() >= size+2){ return 1; }else{ return 2; } }else if(data[position].length() >= size &&data[position].length() < size+2){ if(position+2 > mCount){ return 1; } if(data[position+1].length() < size+2){ return 2; }else { return 1; } }else{ return 1; } } public static class ViewHolder { /** * 该行显示列数 */ public int linecount; /** * 该控件显示在该行位置 */ public int position ; } /** * 获取指定位置的数据 * @param position 数据位置 */ @Override public String getText( int position){ if(position > mCount-1){ return null; } return data[position]; } public void setData(String[]data){ this.data = data; lineCountMap.clear(); columnPositionMap.clear(); if(data == null){ mCount = 0; }else{ mCount = this.data.length; } notifyDataSetChanged(); } }这里需要计算自己的每行显示多少列,以及该项在该行位置分别设置在hoder中设置给每个itemview,需要修改自己计算行数与列数的算法,以及显示的itemview等
新人,有问题请各位大神在下面指出来,谢谢
相关文章推荐
- js自动闭合html标签,自动补全html标记
- 【算法导论】分治策略
- 快速排序总结
- angularjs 前端传递人员验证信息给后台
- 移动IM开发那些事:技术选型和常见问题
- CAP理论和BASE模型
- 【小熊刷题】Binary Tree Maximum Path Sum
- class和struct的区别
- java中的abstract类和interface接口的区别
- 退出远程桌面全屏状态方法
- cocos2dx3.4的多线程bug严重
- ScrollView中嵌套GridView只能显示一行的解决办法
- OTSU算法学习 OTSU公式证明
- Eclipse中SVN插件中英文互相转换方法
- 跟马哥学linux (lesson 1)
- URL中的特殊字符的作用
- 关于图片的处理的一些收集
- HDU4185Oil Skimming(行列匹配||棋盘匹配||黑白染色||1X2矩形覆盖)
- C++函数匹配
- 3Sum Closest