#android
#Android
Вопрос:
Я новичок в Android. В моем проекте у меня есть пользовательский вид MyView со следующим кодом
public class MyView extends View {
private final Bitmap baseBitmap = BitmapFactory.decodeResource(
getResources(), R.drawable.myImage);
private final Matrix matrix;
private boolean active = true;
public MyView(Context context, Matrix matrix) {
super(context);
this.matrix = matrix;
this.setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (active) {
System.out.println("draw " this.getId());
canvas.drawBitmap(baseBitmap, matrix, null);
} else {
...
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("--------->" this.getId());
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
this.invalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
this.active = false;
}
return true;
}
В своей деятельности я много раз создаю экземпляр MyView, а затем добавляю их в основной макет. Это его код:
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
int radius = 80;
double distance = 0, distancePoint = 0;
final int flags = PathMeasure.POSITION_MATRIX_FLAG
| PathMeasure.TANGENT_MATRIX_FLAG;
float length = 0;
setContentView(R.layout.main);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
Path pathCircle = new Path();
pathCircle.addCircle(cx, cy, radius, Direction.CW);
PathMeasure meas = new PathMeasure(pathCircle, false);
int nObject = 10;
length = meas.getLength();
distance = length/nObject;
int i = 0;
while(i<nObject){
Matrix m = new Matrix();
meas.getMatrix((float)distancePoint, m, flags);
MyView myView = new MyView(this, m);
System.out.println(myView.toString());
myView.setId(i);
mainLayout.addView(myView,i);
i ;
distancePoint = distance*i;
}
}
}
Во время выполнения, когда я касаюсь любого элемента MyView, я всегда получаю последний. С помощью « System.out.println("--------->" this.getId());
» я вижу, что идентификатор затронутого элемента всегда является последним, даже если я указываю первый или любой другой элемент. На самом деле, я просто могу переместить последний элемент.
Кто-нибудь знает, почему я не могу получить событие правильного изменения MyView?
(Надеюсь, мой вопрос понятен)
Спасибо
Я изменил код, добавив метод onMeasure. Я использовал код из руководства, размеры не являются специфичными для моего изображения. Представления отображаются, и результат тот же, к сожалению, с той же проблемой. Я также публикую XML-макет, возможно, это может быть полезно.
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
int radius = 80;
double distance = 0, distancePoint = 0;
final int flags = PathMeasure.POSITION_MATRIX_FLAG
| PathMeasure.TANGENT_MATRIX_FLAG;
float length = 0;
setContentView(R.layout.main);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
Path pathCircle = new Path();
pathCircle.addCircle(cx, cy, radius, Direction.CW);
PathMeasure meas = new PathMeasure(pathCircle, false);
int nObject = 10;
length = meas.getLength();
distance = length/nObject;
int i = 0;
while(i<nObject){
Matrix m = new Matrix();
meas.getMatrix((float)distancePoint, m, flags);
MyView myView = new MyView(this, m);
System.out.println(myView.toString());
myView.setId(i);
nt spec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
myView.measure(spec, spec);
mainLayout.addView(myView,i);
i ;
distancePoint = distance*i;
}
}
}
public class MyView extends View {
private final Bitmap baseBitmap = BitmapFactory.decodeResource(
getResources(), R.drawable.myImage);
private final Matrix matrix;
private boolean active = true;
public MyView(Context context, Matrix matrix) {
super(context);
this.matrix = matrix;
this.setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (active) {
System.out.println("draw " this.getId());
canvas.drawBitmap(baseBitmap, matrix, null);
} else {
...
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("--------->" this.getId());
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
this.invalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
this.active = false;
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
setMeasuredDimension(chosenDimension, chosenDimension);
}
private int chooseDimension(int mode, int size) {
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
return size;
} else { // (mode == MeasureSpec.UNSPECIFIED)
return getPreferredSize();
}
}
// in case there is no size specified
private int getPreferredSize() {
return 300;
}
}
The main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@ id/main_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF66FF33">
</RelativeLayout>
Ответ №1:
Я почти уверен, что это потому, что вы в основном размещаете свои представления в верхнем левом углу своего RelativeLayout
. Таким образом, можно коснуться только самого верхнего (последнего добавленного).
Я думаю, что если вы попытаетесь добавить их в LinearLayout
в качестве теста, вы увидите, что ваше представление работает. Программная настройка LayoutParams
для RelativeLayout
не очень удобна, ИМХО.
Редактировать
Я попробовал ваш код. Дело в том, что ваши представления просто созданы для рисования одно поверх другого, иначе общий рисунок не отображался бы, так что мое первое предположение верно (самый верхний покрывает остальные — даже в его прозрачных частях) (кстати, попробуйте Hierarchy Viewer, и вы сможете убедиться в этом сами). Итак, вам нужно выполнять свою работу в одном представлении или обрабатывать касания следующим образом:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if(!isPetaloTouched()) {// check if the actual drawing was touched
return false; // discard the event so that it reaches
// the underlying view
}
//......
Смотрите этот пост для объяснения того, как события работают в Android.
Для обоих способов потребуется isPetaloTouched()
логика, чтобы определить, нужно ли перемещать чертеж, но первый, конечно, был бы более эффективным.
Кроме того, забудьте об onMeasure()
этом, я подумал, что это могло бы помочь придать представлению размер, вокруг которого можно обернуть, чтобы оно не заполняло своего родительского элемента, и имело бы смысл выравнивать представления в сторону. Однако убедитесь, что касание сработало бы, если бы представления не были скоплены.
(…allora mPetali
stava proprio per petali!)
Комментарии:
1. Используя LinearLayout, я получаю только первое представление, поэтому я попытался использовать RelativeLayout. LayoutParams , поэтому я попытался использовать RelativeLayout. Параметры layout отображаются следующим образом RelativeLayout. LayoutParams параметры = новый RelativeLayout. Параметры компоновки (LayoutParams. FILL_PARENT,LayoutParams. WRAP_CONTENT); if(i>0){ params.addRule(RelativeLayout. ALIGN_LEFT,i-1); } MyView.setLayoutParams (параметры); mainLayout.addView(MyView, i); Но это все еще не работает.
2. @vilandra: в
params.addRule()
вам нужно передать идентификатор представления (тот, который вы получаете сgetId()
помощью), а не его индекс в качестве дочернего элемента макета. Возможно, LinearLayout не сработал, потому что вы забыли установитьandroid:orientation="vertical"
. Однако, если это все еще не работает, не могли бы вы проверить с помощью Hierarchy Viewer, занимает ли ваше представление все пространство? Затем вам может потребоваться переопределитьonMeasure()
в вашем пользовательском представлении.3. @bigstones: Невозможно использовать LinearLayout и вертикальную ориентацию, невозможно переопределить onMeasure(), невозможно сохранить предыдущий объект MyView внутри while и вызвать getId вместо использования индекса (это то же самое, потому что я использую индекс для setId, я полагаю). Я действительно не знаю, в чем может быть проблема. Может быть полезно опубликовать код, включающий метод onMeasure?
4. @vilandra
(it's the same thing 'cause I use the index for setId, I suppose)
о, извините, я этого не видел. Да, пожалуйста, опубликуйте и этот код, я надеюсь, что смогу помочь.5. @bigstones: хорошо, мне стыдно за разработчиков! Теперь проблема заключается в том, чтобы узнать фактическое затронутое представление. Я заставил свой View реализовать View. Класс OnTouchListener в конструкторе View установил
code
this.setOnTouchListener(this)code
и в методе onTouch (code
onTouch(View v, событие MotionEvent)code
) проверил полученное представление. Представление всегда является текущим, то есть в моей проблеме представление, переданное в onTouch, всегда является последним, поэтому сравнение междуcode
v.getId()code
иcode
this.getId()code
всегда верно. Таким образом, проблема сохраняется. Затем я использовал ViewGroup, который …