我有一个自定义视图,扩展了ImageView,当我触摸到不同的视图时,我以编程方式添加到FrameLayout。由于某些原因,此自定义视图不会显示在屏幕上,直到第二次触摸触发视图,尽管后续触摸工作正常(自定义视图的新实例不断添加)。编辑:当我昨天发布这个问题时,我忽略了提到在第二次触摸时第一个视图显示出来(即屏幕上有2个视图,当其中一个被拖离另一个时可以看到)。因此,似乎所有点击都得到了妥善处理,问题在于布局的刷新或其他方面的问题。
我已经使用非自定义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 on其他视图时将自定义视图添加到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};
}
}
答案 0 :(得分:0)
此处存在焦点问题,您需要做的是在使用 onClick 的视图上调用requestFocusFromTouch()
。
另外一个问题是,每次单击不必要的按钮时都要重新创建FrameLayout
,只需创建frameLayout
的实例变量,每次单击按钮并使用该实例在其中添加自定义图像视图。
答案 1 :(得分:0)
似乎问题以某种方式与FrameLayout的宽度和高度或ImageView的宽度和高度相关联。 (问题随之消失,因为我改变了两者的尺寸,出于不同的目的。)我还为ImageView设置了scaleType。
以下是问题发生时xml的用法:
<FrameLayout
android:id="@+id/place_art_frame_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black" >
<ImageView
android:id="@+id/place_art_imageview_wall"
android:layout_width="@dimen/wall_large_size"
android:layout_height="@dimen/wall_large_size"
android:layout_gravity="center" />
</FrameLayout>
这是修订后的xml:
<FrameLayout
android:id="@+id/place_art_frame_layout"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@color/black" >
<ImageView
android:id="@+id/place_art_imageview_wall"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter" />
</FrameLayout>