我正在尝试创建一个水平滑动网格的图像。我正在使用带适配器的Gallery视图,为我提供包含要显示的图像视图的TableLayouts。一切看起来都很好,但当我触摸屏幕(MotionEvent.ACTION_DOWN)时,画廊突然向左或向右移动,使得难以滑动(当前显示的孩子被带到前面)。有关如何解决它的任何线索?这是最好的方法吗?
编辑:这里是源代码
import java.util.LinkedList;
import java.util.WeakHashMap;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.SpinnerAdapter;
import android.widget.TableLayout;
import android.widget.TableRow;
public class Dock extends Gallery {
private Adapter mAdapter;
private int numLines=1;
private int numColumns=1;
protected int columnWidth = GridView.AUTO_FIT;
private OnItemClickListener myOnItemClickListener;
private OnItemLongClickListener myOnItemLongClickListener;
private OnItemSelectedListener myOnItemSelectedClickListener;
private GestureDetector interceptGest = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener(){
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return true;
};
});
public int columnSpacing = 10;
private CustomAdapter adapt;
public Dock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initDock();
}
public Dock(Context context, AttributeSet attrs) {
super(context, attrs);
initDock();
}
public Dock(Context context) {
super(context);
initDock();
}
private void initDock(){
this.setSpacing(50);
this.setHorizontalFadingEdgeEnabled(false);
this.setGravity(Gravity.CENTER);
this.setBackgroundColor(Color.GREEN);
this.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
public int getNumLines() {
return numLines;
}
public void setNumLines(int numLines) {
this.numLines = numLines;
}
public int getNumColumns() {
return numColumns;
}
public void setNumColumns(int numColumns) {
this.numColumns = numColumns;
}
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener listener) {
this.myOnItemClickListener = listener;
}
public void setOnItemLongClickListener(
android.widget.AdapterView.OnItemLongClickListener listener) {
this.myOnItemLongClickListener = listener;
}
public void setOnItemSelectedListener(
android.widget.AdapterView.OnItemSelectedListener listener) {
this.myOnItemSelectedClickListener = listener;
}
public void setAdapter(final SpinnerAdapter adapter) {
adapt = new CustomAdapter(adapter);
mAdapter = adapter;
super.setAdapter(adapt);
}
@Override
public SpinnerAdapter getAdapter() {
return (SpinnerAdapter) mAdapter;
}
private class CustomGrid extends TableLayout{
private AdapterView<Adapter> mAdapterView = new AdapterView<Adapter>(getContext()){
@Override
public Adapter getAdapter() {
return mAdapter;
}
@Override
public View getSelectedView() {
return Dock.this.findFocus();
}
@Override
public void setAdapter(Adapter adapter) {
Dock.this.setAdapter((SpinnerAdapter) adapter);
}
@Override
public void setSelection(int position) {
Dock.this.setSelection(position);
}
};
private int page;
private Adapter adapter;
protected android.widget.AdapterView.OnItemClickListener mOnItemClickListener;
protected android.widget.AdapterView.OnItemLongClickListener mOnItemLongClickListener;
protected android.widget.AdapterView.OnItemSelectedListener mOnItemSelectedListener;
public CustomGrid(Context context, AttributeSet attrs) {
super(context, attrs);
initGrid();
}
public CustomGrid(Context context) {
super(context);
initGrid();
}
private void initGrid(){
this.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
this.setFocusable(false);
}
public void setPage(int position) {
this.page = position;
}
public void setAdapter(BaseAdapter adapter) {
this.adapter = adapter;
}
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(
android.widget.AdapterView.OnItemLongClickListener onItemLongClickListener) {
this.mOnItemLongClickListener = onItemLongClickListener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean ret = false;
if(ev.getAction()==MotionEvent.ACTION_MOVE)
ret = true;
else
ret = super.onInterceptTouchEvent(ev);
return ret;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(ev.getAction()==MotionEvent.ACTION_MOVE)
return false;
else
return super.onTouchEvent(ev);
}
public void setOnItemSelectedListener(
android.widget.AdapterView.OnItemSelectedListener onItemSelectedListener) {
this.mOnItemSelectedListener = onItemSelectedListener;
}
private View getCachedView(int position, ViewGroup parent) {
int p = position + page*getNumColumns()*getNumLines();
if(p<adapter.getCount())
return adapter.getView(p, null, parent);
else
return null;
}
private void refreshGrid(){
if(mAdapter==null)
return;
int count=0;
if(numLines>1)
this.setPadding(5, 0, 5, 0);
TableRow line = null;
View view = null;
for(int i = 0; i<numLines; i++){
line = new TableRow(getContext());
line.setBaselineAligned(false);
line.setGravity(Gravity.CENTER);
line.setFocusable(false);
for(int j = 0; j< numColumns; j++){
this.setColumnShrinkable(j, true);
this.setColumnStretchable(j, true);
view = getCachedView(count, line);
if(view!=null){
final int position = count + page*getNumColumns()*getNumLines();
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(mOnItemClickListener!=null)
mOnItemClickListener.onItemClick(mAdapterView, arg0, position, mAdapter.getItemId(position));
}
});
view.setOnLongClickListener( new OnLongClickListener() {
@Override
public boolean onLongClick(View arg0) {
if(mOnItemLongClickListener!=null)
return mOnItemLongClickListener.onItemLongClick(mAdapterView, arg0, position, mAdapter.getItemId(position));
else return false;
}
});
view.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View arg0, boolean arg1) {
if(mOnItemSelectedListener!=null&&arg1){
mOnItemSelectedListener.onItemSelected(mAdapterView, arg0, position, mAdapter.getItemId(position));
}
}
});
view.setFocusable(false);
line.addView(view);
}
count++;
}
if(numLines>1)
while(line.getChildCount()<numColumns){
View v = this.getEmptyView();
v.setFocusable(false);
line.addView(v);
}
this.addView(line);
}
}
private View getEmptyView() {
ImageView ret = new ImageView(getContext());
ret.setBackgroundColor(Color.TRANSPARENT);
return ret;
}
}
private class CustomAdapter extends BaseAdapter{
private WeakHashMap<Integer,CustomGrid> cache = new WeakHashMap<Integer,CustomGrid>();
private LinkedList<Integer> cacheId = new LinkedList<Integer>();
private Adapter adapter;
public CustomAdapter(Adapter a){
super();
adapter = a;
}
public long getItemId(int position) {
return position;
}
public Object getItem(int position) {
return null;
}
public int getCount() {
int n = adapter.getCount()/(numColumns*numLines);
if(adapter.getCount()%(numColumns*numLines)!=0)
n++;
return n;
}
private CustomGrid getPage(final int position){
CustomGrid ret = new CustomGrid(getContext());
ret.setPage(position);
ret.setAdapter((BaseAdapter) adapter);
ret.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterV, View v,
int pos, long id) {
//int page = position;
if(myOnItemClickListener!=null){
myOnItemClickListener.onItemClick(adapterV, v, pos, adapter.getItemId(pos));
}
}
});
ret.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> adapterV,
View arg1, int pos, long arg3) {
//int page = position;
if(myOnItemLongClickListener!=null){
return myOnItemLongClickListener.onItemLongClick(adapterV, arg1, pos, adapter.getItemId(pos));
}
else
return false;
}
});
ret.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterV,
View arg1, int pos, long arg3) {
if(myOnItemSelectedClickListener!=null){
myOnItemSelectedClickListener.onItemSelected(adapterV, arg1, pos, adapter.getItemId(pos));
}
}
public void onNothingSelected(AdapterView<?> arg0) {
if(myOnItemSelectedClickListener!=null)
myOnItemSelectedClickListener.onNothingSelected(arg0);
}
});
ret.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
ret.setGravity(Gravity.CENTER);
ret.setBackgroundColor(Color.BLUE);
ret.refreshGrid();
return ret;
}
public View getView(int position, View convertView, ViewGroup parent) {
convertView = cache.get(position);
if(convertView==null){
convertView = getPage(position);
while(cache.size()>3){
cache.remove(cacheId.removeFirst());
}
cache.put(position, (CustomGrid) convertView);
cacheId.add(position);
if(position<getCount()){
cache.put(position+1, getPage(position+1));
cacheId.add(position+1);
}
}
return convertView;
}
public void flush() {
cache.clear();
cacheId.clear();
}
};
public void setColumnWidth(int width) {
this.columnWidth = width;
}
public void setColumnMargin(int margin){
this.columnSpacing = margin;
}
private MotionEvent primTouch;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if(e1!=null&&e2!=null){
float dist = e1.getX()-e2.getX();
if(Math.abs(dist)>30){
if(dist>0)
return onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_RIGHT));
else
return onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));
}
}
return true;
}
private MotionEvent interm;
private boolean scrollingHorizontally=false;
public void flush(){
adapt.flush();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(ev.getAction()==MotionEvent.ACTION_DOWN)
primTouch = ev;
if(ev.getAction()==MotionEvent.ACTION_MOVE)
return true;
else
return scrollingHorizontally;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
scrollingHorizontally = true;
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
primTouch=event;
return super.onTouchEvent(event);
case MotionEvent.ACTION_MOVE:
scrollingHorizontally=true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
scrollingHorizontally = false;
if(primTouch!=null){
float dist = primTouch.getX()-event.getX();
if(Math.abs(dist)>30){
if(dist>0)
return onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_RIGHT));
else
return onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));
}
}
break;
}
return super.onTouchEvent(event);
}
}
编辑2:我发现如果我处理函数onInterceptTouchEvent(MotionEvent ev)中的所有触摸事件(当我将其设置为始终返回true时),问题会消失,但禁用了在子项上设置的任何onClickListener。如果您使用onItemClickListener,或者如果您确切知道子结构一旦检测到就会调度点击,那就没关系了。