【发布时间】:2014-08-12 18:37:34
【问题描述】:
我有一个自定义视图,扩展了 ImageView,当触摸不同的视图时,我以编程方式将其添加到 FrameLayout。由于某种原因,此自定义视图直到第二次触摸触发视图时才会显示在屏幕上,尽管后续触摸工作正常(自定义视图的新实例不断添加)。 编辑:当我昨天发布这个问题时,我忽略了在第二次触摸时显示第一个视图(即,屏幕上有两个视图,当一个被拖离另一个视图时,这两个视图都可以看到)。因此,似乎所有点击都得到了正确处理,问题在于布局的刷新或类似的事情。
我已经用非自定义 ImageView 进行了测试,但没有发现这个问题,我还更改了自定义视图以扩展 View,而不是 ImageView,这个问题消失了,但是一个新问题取而代之——将视图添加到 FrameLayout 会对整体布局产生奇怪的影响(FrameLayout 似乎向下移动或增长,并且 FrameLayout 下方的布局不再可见)。
我在这里尝试了解决方案:Refreshing a LinearLayout after adding a view,但这没有帮助。
以下是将自定义视图添加到 FrameLayout 的代码:
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.place_art_frame_layout);
WallArtView wallArtView = new WallArtView(getApplicationContext());
wallArtView.initWallArt(artWork, 100, 300, viewBoundary(wall));
wallArtView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
frameLayout.addView(wallArtView);
我尝试在上述代码之后对视图和 FrameLayout 调用 invalidate,但均无济于事。
这是自定义视图的代码:
public class WallArtView extends ImageView {
Canvas canvas;
private int windowWidth;
private int windowHeight;
float mLastTouchX = 0;
float mLastTouchY = 0;
private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
WallArt wallArt;
Rect rect;
int movementBoundary[];
Paint paint;
public WallArtView(Context context) {
super(context);
setFocusable(true); // necessary for getting the touch events
canvas = new Canvas();
rect = new Rect();
paint = new Paint();
}
public WallArtView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public WallArtView(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true); // necessary for getting the touch events
canvas = new Canvas();
windowWidth = getContext().getResources().getDisplayMetrics().widthPixels;
windowHeight = getContext().getResources().getDisplayMetrics().heightPixels;
rect = new Rect();
paint = new Paint();
}
public float getWindowWidth() {
return windowWidth;
}
public float getWindowHeight() {
return windowHeight;
}
public void initWallArt(Bitmap b, float l, float t, int[] boundary) {
wallArt = new WallArt(b, l, t);
movementBoundary = boundary;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#44FFFFFF"));
paint.setStrokeWidth(0);
canvas.drawRect(200, 500, 500, 1000, paint);
// draw the art
rect.set((int) wallArt.getLeft(), (int) wallArt.getTop(),
(int) wallArt.getLeft() + wallArt.getWidthOfArt(),
(int) wallArt.getTop() + wallArt.getHeightOfArt());
canvas.drawBitmap(wallArt.getBitmap(), null, rect, null);
canvas.restore();
}
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
float X = event.getX();
float Y = event.getY();
switch (eventaction) {
case MotionEvent.ACTION_DOWN: // touch down so check if the finger is on
final int pointerIndex = MotionEventCompat.getActionIndex(event);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);
// Remember where we started (for dragging)
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer (for dragging)
mActivePointerId = MotionEventCompat.getPointerId(event, 0);
break;
case MotionEvent.ACTION_MOVE: // touch drag with the ball
final int pointerIndex1 = MotionEventCompat.findPointerIndex(event, mActivePointerId);
final float x1 = MotionEventCompat.getX(event, pointerIndex1);
final float y1 = MotionEventCompat.getY(event, pointerIndex1);
// Calculate the distance moved
final float dx = x1 - mLastTouchX;
final float dy = y1 - mLastTouchY;
// Remember this touch position for the next move event
mLastTouchX = x1;
mLastTouchY = y1;
float artLeft = wallArt.getLeft();
float artRight = wallArt.getLeft() + wallArt.getWidthOfArt();
float artTop = wallArt.getTop();
float artBottom = wallArt.getTop() + wallArt.getHeightOfArt();
if (X > artLeft && X < artRight && Y > artTop && Y < artBottom
&& (artLeft > movementBoundary[0] || dx > 0)
&& (artTop > movementBoundary[1] || dy > 0)
&& (artRight < movementBoundary[2] || dx < 0)
&& (artBottom < movementBoundary[3] || dy < 0)) {
wallArt.setLeft(wallArt.getLeft() + dx);
wallArt.setTop(wallArt.getTop() + dy);
}
break;
case MotionEvent.ACTION_UP:
// touch drop - just do things here after dropping
break;
}
// redraw the canvas
invalidate();
return true;
}
public static class WallArt {
Bitmap bitmap;
float left, top;
int id;
static int count = 0;
public WallArt(Bitmap b, float l, float t) {
this.id = count++;
bitmap = b;
left = l;
top = t;
}
public int getWidthOfArt() {
return bitmap.getWidth();
}
public int getHeightOfArt() {
return bitmap.getHeight();
}
public Bitmap getBitmap() {
return bitmap;
}
public float getLeft() {
return left;
}
public float getTop() {
return top;
}
public int getID() {
return id;
}
public void setLeft(float l) {
left = l;
}
public void setTop(float t) {
top = t;
}
}
}
提前感谢您的帮助。
编辑:以下是在 onClick 不同视图发生时将自定义视图添加到 FrameLayout 的完整代码:
public class ActivityWallPlaceArt extends Activity implements OnClickListener{
private ImageView thumbNail, wall;
private Bitmap artWork;
private WallArtView wallArtView;
private FrameLayout frameLayout;
private Button done;
private Context context;
private int mWallIndex = 0;
private int mRoomIndex = 0;
private String mThumbnailUrl;
ArrayList<Wall> mWallList;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wall_place_art);
artWork = bitmapFromFile("/storage/emulated/0/Pictures/Curate/IMG_20140808_132606.jpg");
wall = (ImageView) findViewById(R.id.place_art_imageview_wall);
wall.setImageBitmap(bitmapFromFile("/storage/emulated/0/Pictures/Curate/IMG_20140731_170538.jpg"));
thumbNail = (ImageView) findViewById(R.id.place_art_imageview_thumbnail);
thumbNail.setImageBitmap(artWork);
thumbNail.setOnClickListener(this);
thumbNail.requestFocus();
frameLayout = (FrameLayout) findViewById(R.id.place_art_frame_layout);
// -------------
context = getApplicationContext();
Intent intent = getIntent();
mWallIndex = intent.getIntExtra("wallIndex",0);
mRoomIndex = intent.getIntExtra("roomIndex",0);
mThumbnailUrl = intent.getStringExtra("thumbnailUrl");
mWallList = ActivityMain.sRoomList.getRoom(mRoomIndex).getWallList();
Wall currentWall = mWallList.get(mWallIndex);
done = (Button) findViewById(R.id.place_art_imageview_done);
done.setOnClickListener(this);
}
private Bitmap bitmapFromFile(String imageUrl) {
Bitmap bitmap = null;
try {
final File file = new File(imageUrl);
BitmapFactory.Options option = new BitmapFactory.Options();
option.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file), null, option);
final int REQUIRED_WIDTH = 200;
final int REQUIRED_HIGHT = 200;
int scale = 1;
while (option.outWidth / scale / 2 >= REQUIRED_WIDTH
&& option.outHeight / scale / 2 >= REQUIRED_HIGHT)
scale *= 2;
BitmapFactory.Options optionObj = new BitmapFactory.Options();
optionObj.inSampleSize = scale;
Uri uri = Uri.parse(imageUrl);
ExifInterface exif;
try {
exif = new ExifInterface(uri.getPath());
int rotation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
Matrix mat = new Matrix();
mat.postRotate(rotationInDegrees);
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, optionObj);
bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), mat, true);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
}
return bitmap;
}
private static int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
return 0;
}
@Override
public void onClick(View v) {
if (v == thumbNail) {
wallArtView = new WallArtView(getApplicationContext());
wallArtView.initWallArt(artWork, 100, 300, viewBoundary(wall));
wallArtView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
frameLayout.addView(wallArtView);
}
else if (v == done) {
finish();
}
}
private int[] viewBoundary(View view) {
int[] l = new int[2];
view.getLocationOnScreen(l);
int x = l[0];
int y = l[1];
int w = view.getWidth();
int h = view.getHeight();
return new int[] {x, y, x + w, y + h};
}
}
【问题讨论】:
-
你所说的
when a different view is touched on是什么意思 -
@Rod_Algonquin 我在不同的布局中有一个不同的视图,它有一个与之关联的 onClickListener。我上面第一个 sn-p 中的代码在
onClick()中,用于该侦听器。
标签: android android-layout android-custom-view