Problem with large views inside gallery
I'm trying to create an horizontal sliding grid of image. I'm using a Gallery view with an adapter providing me TableLayouts containing the images view to display. Everything looks fine, but when I touch the screen (MotionEvent.ACTION_DOWN), the Gallery move abruptly to the left or right, making it difficult to swipe (the currently displayed child is brought to the front). Any clue on how to fix it ? Is this the best approach ?
Edit: Here the source code
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() {
@Overr开发者_Python百科ide
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);
}
}
EDIT 2: I figured out that if I handle all the touch events in function onInterceptTouchEvent(MotionEvent ev) (when I set it to always return true), the problem disapear but any onClickListener set on the child is disabled. It'll be fine if you use the onItemClickListener or if you know precisely the child structure to dispatch the click once detected.
gallery has a center locking mechanism which will make it hard while sypeing. you can try this LINK.
i have seen this in action and will pretty will suit what you are doing.
精彩评论