Пользовательская картинка для Android
Я просто хочу поделиться этим фрагментом кода, который я написал. Я попытался выполнить поиск пользовательской активности, но большинство из них приводит к по умолчанию "com.android.camera.action.CROP", несмотря на вопрос о пользовательской культуре или активности ручной работы. Во всяком случае, я просто сделал один для себя, и, надеюсь, это поможет вам, ребята.
public class CropView extends ImageView {
Paint paint = new Paint();
private int initial_size = 300;
private static Point leftTop, rightBottom, center, previous;
private static final int DRAG= 0;
private static final int LEFT= 1;
private static final int TOP= 2;
private static final int RIGHT= 3;
private static final int BOTTOM= 4;
private int imageScaledWidth,imageScaledHeight;
// Adding parent class constructors
public CropView(Context context) {
super(context);
initCropView();
}
public CropView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initCropView();
}
public CropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCropView();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(leftTop.equals(0, 0))
resetPoints();
canvas.drawRect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
previous.set((int)event.getX(), (int)event.getY());
break;
case MotionEvent.ACTION_MOVE:
if(isActionInsideRectangle(event.getX(), event.getY())) {
adjustRectangle((int)event.getX(), (int)event.getY());
invalidate(); // redraw rectangle
previous.set((int)event.getX(), (int)event.getY());
}
break;
case MotionEvent.ACTION_UP:
previous = new Point();
break;
}
return true;
}
private void initCropView() {
paint.setColor(Color.YELLOW);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(5);
leftTop = new Point();
rightBottom = new Point();
center = new Point();
previous = new Point();
}
public void resetPoints() {
center.set(getWidth()/2, getHeight()/2);
leftTop.set((getWidth()-initial_size)/2,(getHeight()-initial_size)/2);
rightBottom.set(leftTop.x+initial_size, leftTop.y+initial_size);
}
private static boolean isActionInsideRectangle(float x, float y) {
int buffer = 10;
return (x>=(leftTop.x-buffer)&&x<=(rightBottom.x+buffer)&& y>=(leftTop.y-buffer)&&y<=(rightBottom.y+buffer))?true:false;
}
private boolean isInImageRange(PointF point) {
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Calculate the scaled dimensions
imageScaledWidth = Math.round(getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
imageScaledHeight = Math.round(getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);
return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
}
private void adjustRectangle(int x, int y) {
int movement;
switch(getAffectedSide(x,y)) {
case LEFT:
movement = x-leftTop.x;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case TOP:
movement = y-leftTop.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case RIGHT:
movement = x-rightBottom.x;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case BOTTOM:
movement = y-rightBottom.y;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case DRAG:
movement = x-previous.x;
int movementY = y-previous.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movementY)) && isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movementY))) {
leftTop.set(leftTop.x+movement,leftTop.y+movementY);
rightBottom.set(rightBottom.x+movement,rightBottom.y+movementY);
}
break;
}
}
private static int getAffectedSide(float x, float y) {
int buffer = 10;
if(x>=(leftTop.x-buffer)&&x<=(leftTop.x+buffer))
return LEFT;
else if(y>=(leftTop.y-buffer)&&y<=(leftTop.y+buffer))
return TOP;
else if(x>=(rightBottom.x-buffer)&&x<=(rightBottom.x+buffer))
return RIGHT;
else if(y>=(rightBottom.y-buffer)&&y<=(rightBottom.y+buffer))
return BOTTOM;
else
return DRAG;
}
public byte[] getCroppedImage() {
BitmapDrawable drawable = (BitmapDrawable)getDrawable();
float x = leftTop.x-center.x+(drawable.getBitmap().getWidth()/2);
float y = leftTop.y-center.y+(drawable.getBitmap().getHeight()/2);
Bitmap cropped = Bitmap.createBitmap(drawable.getBitmap(),(int)x,(int)y,(int)rightBottom.x-(int)leftTop.x,(int)rightBottom.y-(int)leftTop.y);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream);
return stream.toByteArray();
}
}
Что я сделал, я расширил ImageView и добавил возможности Cropping. Он довольно прост в использовании. Как только класс будет сохранен, просто используйте его в макете, как это.
<"your package name".CropView
android:id="@+id/image_preview"
android:layout_width="fill_parent"
android:layout_height="match_parent" />
Вот оно! Надеюсь, поможет! Если вы столкнулись с какой-либо проблемой, не стесняйтесь спрашивать:)
Ответы
Ответ 1
Вы должны попробовать:
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.crop_layout);
myCropView = new CropView(this);
Uri imageUri = getIntent().getExtras().getParcelable("path");
b = (BitmapDrawable) BitmapDrawable.createFromPath(imageUri.getPath());
myCropView.setImageURI(imageUri);
}
(Взято из редактирования на ваш вопрос.)
Ответ 2
спасибо thehippo... но я решил найти вид по макету
Uri imageUri = getIntent().getExtras().getParcelable("path");
b = (BitmapDrawable) BitmapDrawable.createFromPath(getRealPathFromURI(imageUri));
myCropView = (CropView) findViewById(R.id.image_preview);
myCropView.setBackground(b);
но теперь я не могу обработать событие touch. Прямоугольник остается неподвижным, даже если я касаюсь экрана...
EDIT: хорошо, я сделал это работает. Но теперь прямоугольник перемещается только внутри меньшей области, а не по всему изображению. Я полагаю, что здесь что-то не так.
private boolean isInImageRange(PointF point) {
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Calculate the scaled dimensions
imageScaledWidth = Math.round(getBackground().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
imageScaledHeight = Math.round(getBackground().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);
return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
}
Я сделал небольшое изменение, чтобы заставить работать код: getBackground() вместо getDrawable
ИЗМЕНИТЬ 2: ОК, у меня это получилось, я делал это неправильно. Вы код хороший. Чтобы установить изображение, я использовал view.seBackground()... вместо view.setImageDrawable(). Теперь все работает. Возможно, я только проверю, возможно ли создать большую область, которая запускает масштабирование прямоугольника
Ответ 3
Я нашел библиотеку, которая поддерживает это: SimpleCropView из https://android-arsenal.com/details/1/2366. В общем, я бы не рекомендовал его, его производительность далека от приложений для андроидных обрезков.
Я пробовал использовать его, и мои мысли таковы:
-
На самом деле, просто реализовать в вашем приложении, мне потребовалось около 5 минут, чтобы получить функциональность обрезки и ротации, работающую с моим существующим приложением
-
Повторная калибровка области обрезки болезненно медленная, я бы не хотел, чтобы мой пользователь ее видел.
UPDATE:
Фактически, я нашел действительно хорошее решение как jdamcd/android-crop в Github: https://github.com/jdamcd/android-crop
Краткое описание:
-
Очень прост в использовании в вашем приложении
-
Быстро, так как он использует код из собственного приложения галереи
-
Настраивается, если вы хотите провести некоторое время с ним. По умолчанию он предоставляет вам действие, в котором выполняется обрезка. Если вы хотите интегрировать его в свою собственную деятельность, это займет немного времени. (Для моего проекта я бы хотел интегрировать его и буду делать в будущем, но на данный момент достаточно отдельного действия).
Надеюсь, что это дает некоторое представление!