I am trying to capture image within the rectangle as shown in image, using CameraX.
The way I am going on about this is, by having the ratio of Screen to Caputred image calculated and then mapping the rectangle visible in camera to another rectangle(equivalent to the captured image) and then cropping the bitmap. The code is as follows.
fragment_scan_doc.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/clRoot"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/gdl_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="28dp" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_25dp"
android:text="#string/app_name"
android:textColor="#color/black"
android:textSize="#dimen/text_size_24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="#id/gdl_right"
app:layout_constraintStart_toStartOf="#id/gdl_left"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvDesc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_16dp"
android:text="#string/place_doc"
android:textColor="#color/black"
app:layout_constraintEnd_toEndOf="#+id/gdl_right"
app:layout_constraintStart_toStartOf="#+id/gdl_left"
app:layout_constraintTop_toBottomOf="#+id/tvTitle" />
<androidx.camera.view.PreviewView
android:id="#+id/previewView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="#dimen/dimen_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvDesc" />
<TextView
android:id="#+id/tvCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13dp"
android:background="#drawable/bg_round_white_solid_yellow_stripe"
android:gravity="center"
android:paddingStart="#dimen/dimen_25dp"
android:paddingTop="#dimen/dimen_10dp"
android:paddingEnd="#dimen/dimen_25dp"
android:paddingBottom="#dimen/dimen_10dp"
android:text="Front"
android:textColor="#color/black"
app:layout_constraintEnd_toEndOf="#id/gdl_right"
app:layout_constraintStart_toStartOf="#id/gdl_left"
app:layout_constraintTop_toTopOf="#+id/previewView" />
<View
android:id="#+id/border_view"
android:layout_width="325dp"
android:layout_height="202.5010436dp"
android:background="#drawable/bg_round_grey_stripe"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#id/gdl_right"
app:layout_constraintStart_toStartOf="#id/gdl_left"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvPoweredBy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Powered by"
android:textColor="#color/white"
app:layout_constraintEnd_toEndOf="#id/gdl_right"
app:layout_constraintStart_toStartOf="#id/gdl_left"
app:layout_constraintTop_toBottomOf="#+id/border_view" />
<View
android:id="#+id/vTakePhoto"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginBottom="20dp"
android:background="#drawable/bg_round_white_solid_stripe"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<ImageView
android:id="#+id/ivFlash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:background="#drawable/bg_circle_white_solid"
android:padding="10dp"
android:src="#drawable/ic_baseline_flash_off_24"
app:layout_constraintBottom_toBottomOf="#+id/vTakePhoto"
app:layout_constraintStart_toEndOf="#+id/vTakePhoto"
app:layout_constraintTop_toTopOf="#+id/vTakePhoto" />
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="50dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/gdl_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="28dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is the place where I get Image from camerax and I submit it to the cropImage() function
private fun takePhoto() {
imageCapture?.takePicture(ContextCompat.getMainExecutor(requireContext()),
object : ImageCapture.OnImageCapturedCallback() {
#SuppressLint("UnsafeOptInUsageError")
override fun onCaptureSuccess(imageProxy: ImageProxy) {
val image = imageProxy.image?.let { image ->
InputImage.fromMediaImage(
image,
imageProxy.imageInfo.rotationDegrees
)
}
cropImage(imageProxy)
}
override fun onError(exception: ImageCaptureException) {
exception.printStackTrace()
}
})
}
This is the cropImage() function
private fun cropImage(imageProxy: ImageProxy) {
val ori = imageProxy.convertImageProxyToBitmap().rotate(90f)
val rect = Rect()
mViewBinding.borderView.getGlobalVisibleRect(rect)
val screenWidth = mViewBinding.root.width
val screenHeight = mViewBinding.root.height
val ratioW = screenWidth.toFloat() / ori.width // I am trying to get the ratio of screen to image width
val ratioH = screenHeight.toFloat() / ori.height
val x1 = rect.left / ratioW
val y1 = rect.top / ratioH
val x1W = rect.right / ratioW
val x1H = rect.bottom / ratioH
val rect1 = Rect(x1.toInt(), y1.toInt(), x1W.toInt(), x1H.toInt())
val cropedBm = Bitmap.createBitmap(
ori,
rect1.left,
rect1.top,
rect1.right - rect1.left,
rect1.bottom - rect1.top
)
processNewBitmap(cropedBm) // this is where I display the cropped bitmap and it appears like in the image below
}
The image is cropped a bit below the rectangle frame.
I am not quite sure what I am doing wrong. Any help or direction would be highly appreciated. Thanks
your ImageProxy has a bitmap you want to crop with a view overlay that does not same width or height. You must calculate with scale ratio.
You can refer to this link:
https://www.codeproject.com/Articles/1276135/Crop-Image-from-Camera-on-Android
Related
Is anyone aware of how to position the buttons vertically if the button text is too long inside of the xml?
I want the buttons to be positioned horizontally if they fit, if one of the buttons has to hyphenate, then I would like to avoid that by positioning the buttons below each other. Is there a way to do it inside of the XML only?
Thanks!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/tv_header"
style="#style/TitleTextAppearance.WithPrimaryBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/header_enter_startcode" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dialog_background_with_margin">
<TextView
android:id="#+id/tv_status"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/pls_enter_startcode"
android:textSize="#dimen/text_size_default"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/til_startcode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="#dimen/grid_2"
app:helperText="#string/example_startcode"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tv_status">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/tiet_startcode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:maxLines="1"
android:textStyle="bold" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/gl_middle"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_percent="0.5"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="#+id/btn_continue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/grid_2"
android:layout_marginTop="#dimen/grid_2"
android:layout_marginEnd="#dimen/grid_2"
android:text="#string/btn_continue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/gl_middle"
app:layout_constraintTop_toBottomOf="#+id/til_startcode" />
<com.google.android.material.button.MaterialButton
android:id="#+id/btn_cancel"
style="?materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/grid_2"
android:layout_marginTop="#dimen/grid_2"
android:layout_marginEnd="#dimen/grid_2"
android:text="#string/cancel"
app:layout_constraintEnd_toStartOf="#+id/gl_middle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/til_startcode" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
I was able to solve this problem by creating a custom view which extends ConstraintLayout Flow. (Kudos #guglhupf for suggestion).
This should also adapt to when Foldable device is being folded.
Kotlin
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.Button
import androidx.constraintlayout.helper.widget.Flow
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.allViews
import androidx.core.view.updateLayoutParams
internal class FlexLayout(context: Context, attrs: AttributeSet) : Flow(context, attrs) {
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
makeChildrenMatchParentIfTheyArePositionedVertically()
}
private fun makeChildrenMatchParentIfTheyArePositionedVertically() {
allViews.forEach { flexLayoutCandidate ->
(flexLayoutCandidate as? FlexLayout)?.let { flexLayout ->
val mutableMapOfYCoordinatesAndView = mutableMapOf<View, Int>()
//Check all the Id's that Flow layout is referencing and store them in a map
flexLayout.referencedIds.forEach { referenceId ->
val foundView = rootView.findViewById<View>(referenceId)
if (foundView != null) {
val locationOnScreen = IntArray(size = 2)
foundView.getLocationOnScreen(locationOnScreen)
Log.d("FlexLayout", "Name ${(foundView as? Button)?.text}")
Log.d("FlexLayout", "Location on screen: x = ${locationOnScreen[0]} y = ${locationOnScreen[1]}")
mutableMapOfYCoordinatesAndView[foundView] = locationOnScreen[1]
}
}
var previousMapEntry: Map.Entry<View, Int>? = null
mutableMapOfYCoordinatesAndView.forEach loopToCompareWhetherTheYCoordinatesAreDifferent#{
val currentMapEntry = it
if (previousMapEntry == null) {
previousMapEntry = currentMapEntry
return#loopToCompareWhetherTheYCoordinatesAreDifferent
}
//Check if Flow layout decided to put the view on the next line
if (previousMapEntry?.value != currentMapEntry.value) {
previousMapEntry?.key?.updateLayoutParams<ConstraintLayout.LayoutParams> {
width = ConstraintLayout.LayoutParams.MATCH_PARENT
}
currentMapEntry.key.updateLayoutParams<ConstraintLayout.LayoutParams> {
width = ConstraintLayout.LayoutParams.MATCH_PARENT
}
}
previousMapEntry = currentMapEntry
}
}
}
}
}
XML
<company.name.customview.FlexLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="#dimen/margin_between_view_blocks"
app:constraint_referenced_ids="btn_dialog_negative, btn_dialog_positive"
app:flow_horizontalGap="#dimen/space_between_two_buttons"
app:flow_horizontalStyle="spread_inside"
app:flow_verticalGap="#dimen/space_between_two_buttons"
app:flow_wrapMode="aligned"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#id/tv_dialog_body"
app:layout_constraintStart_toStartOf="#id/tv_dialog_body"
app:layout_constraintTop_toBottomOf="#+id/tv_dialog_body" />
You can put the elements in a Flow helper and configure it to automatically wrap. Remove the unnecessary constraints from btn_continue and btn_cancel
<androidx.constraintlayout.helper.widget.Flow
android:id="#+id/flow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/grid_2"
android:layout_marginStart="#dimen/grid_2"
android:layout_marginEnd="#dimen/grid_2"
app:constraint_referenced_ids="btn_continue,btn_cancel"
app:flow_horizontalGap="#dimen/grid_2"
app:flow_horizontalStyle="spread"
app:flow_wrapMode="aligned"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/til_startcode" />
<com.google.android.material.button.MaterialButton
android:id="#+id/btn_continue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/btn_continue"/>
<com.google.android.material.button.MaterialButton
android:id="#+id/btn_cancel"
style="?materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/cancel" />
I am trying to display # user mentions like facebook or twitter. I am able to implement this functionality. But i have a ui problem.
If edittext is at the bottom of the screen i need to show suggestion in recyclerview at the top.(above edittext cursor)
If edittext is at the top of the screen i need to show suggestion in recycelrview at the bottom (below edittext cursor)
What have i tried?
I have used recyclerview that is constrained below edittext
Problem
When soft keyboard opens it covers the recyclerview. This happens when edittext cursor is at the bottom.
How can i fix this using existing recyclerview itself?.
When edittext cursor is at the top see suggestions are shown below properly.
Code
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textStyle="bold"
android:textSize="16sp"
android:textColor="#color/black"
android:fontFamily="#font/source_sans_pro"
android:id="#+id/titleHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/create_feed_post"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/line"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="#c8c8c8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/titleHeader" />
<com.linkedin.android.spyglass.ui.MentionsEditText
android:padding="8dp"
android:id="#+id/mentionsEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="300dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="#null"
android:gravity="start|top"
android:hint="Share team wins or recognize colleague for a job well done"
android:inputType="textMultiLine"
android:minHeight="50dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/line">
</com.linkedin.android.spyglass.ui.MentionsEditText>
<ImageView
android:id="#+id/preview"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mentionsEditText" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:layout_width="0dp"
android:layout_height="250dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:elevation="5dp"
android:orientation="vertical"
android:overScrollMode="never"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="none"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mentionsEditText" />
<View
android:id="#+id/line2"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="8dp"
android:background="#c8c8c8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/preview" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/optionsContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/line2">
<ImageView
android:id="#+id/visibility"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:src="#drawable/toggle_comment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/attach"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_upload_image" />
<Button
android:id="#+id/done"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="32dp"
android:text="#string/post"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#id/visibility"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="#id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="#+id/titleHeader"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/titleHeader"
app:srcCompat="#drawable/ic_close"
app:tint="#color/black" />
<FrameLayout
android:visibility="gone"
android:elevation="5dp"
android:id="#+id/container"
app:layout_constraintBottom_toTopOf="#+id/preview"
app:layout_constraintEnd_toEndOf="#+id/preview"
app:layout_constraintTop_toTopOf="#+id/preview"
android:layout_width="20dp"
android:layout_height="20dp">
<com.mikhaellopez.circleview.CircleView
app:cv_border_width="1dp"
app:cv_border_color="#EAEAEA"
app:cv_border="true"
app:cv_color="#color/white"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:layout_gravity="center"
android:id="#+id/removePreview"
android:layout_width="15dp"
android:layout_height="15dp"
app:srcCompat="#drawable/ic_close"
app:tint="#999999" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
Update: i tried using a pop up window. I am able to show above or below a view depending on where the view is located. But there is still one problem with keyboard opening. The pop up comes over the keyboard when the edittext is at the bottom. The edittext moves up but popup window stays in same place
Update 2:
if(anchor instanceof EditText) {
EditText editText = (EditText) anchor;
int pos = editText.getSelectionStart();
Layout layout = editText.getLayout();
int line = layout.getLineForOffset(pos);
int baseline = layout.getLineBaseline(line);
int ascent = layout.getLineAscent(line);
float cursorx = layout.getPrimaryHorizontal(pos);
cursory = baseline + ascent- editText.getScrollY();
}
final View contentView = view;
final Rect windowRect = new Rect();
contentView.getWindowVisibleDisplayFrame(windowRect);
final int windowW = windowRect.width();
final int windowH = windowRect.height();
contentView.measure(
makeDropDownMeasureSpec(getWidth(), windowW),
makeDropDownMeasureSpec(getHeight(), windowH)
);
final int measuredW = contentView.getMeasuredWidth();
final int measuredH = contentView.getMeasuredHeight();
final int[] anchorLocation = new int[2];
anchor.getLocationInWindow(anchorLocation);
final int anchorBottom = anchorLocation[1] + anchor.getHeight();
if (y + anchorBottom < 0) {
y = -anchorBottom;
} else {
y = (int) (y + cursory );
}
And then
popupWindow.showAsDropDown(anchor, 0, y);
and the flag in manifest is
android:windowSoftInputMode="adjustResize"
Using pop up window show at location will fix this
private fun showPopupWindow(anchor: View) {
var popUpHeight = 0
PopupWindow(anchor.context).apply {
isOutsideTouchable = true
val inflater = from(anchor.context)
contentView = inflater.inflate(R.layout.popup_layout, null).apply {
measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
measuredWidth
measuredHeight
popUpHeight = measuredHeight
}
height = ViewGroup.LayoutParams.WRAP_CONTENT
width = ViewGroup.LayoutParams.MATCH_PARENT
}.also { popupWindow ->
val location = IntArray(2).apply {
anchor.getLocationInWindow(this)
}
val size = Size(
popupWindow.contentView.measuredWidth,
popupWindow.contentView.measuredHeight
)
val editText = anchor as EditText
val pos = editText.selectionStart
val layout: Layout = editText.layout
val line: Int = layout.getLineForOffset(pos)
editText.getLocationOnScreen(location)
val point = Point()
point.x = layout.getPrimaryHorizontal(pos).toInt()
point.y = layout.getLineBottom(line)// location[1] //- (baseline + ascent )
val y = point.y
val top = layout.getLineTop(line)
val editTextheight = editText.measuredHeight
val yOffset = if (y > (editTextheight / 2)) {
top - (popUpHeight + 50)
} else {
point.y + 50
}
popupWindow.showAsDropDown(
anchor, 0,
yOffset
)
}
}
Based on where the cursor is and also the height of edittext you can calculate the yoffset and show the pop up at a specified position.
In case edittext scrolls you can use editText.scrolly and re-calculate your offset.
I am trying to create button C programmatically, but can not get the size below 231 pixels. The XML Buttons have 157 pixels width.
How do I make the button same size as the others?
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/label_enter_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="50dp"
android:text="#string/enter_code_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/code_1"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:inputType="textCapCharacters"
android:maxLength="2"
android:text="A1"
android:textAlignment="center"
android:textSize="#dimen/text_big"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintStart_toStartOf="#+id/label_enter_code"
app:layout_constraintTop_toBottomOf="#id/label_enter_code" />
<EditText
android:id="#+id/code_2"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/text_big"
android:inputType="textCapCharacters"
android:maxLength="2"
android:text="B2"
android:textAlignment="center"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="#id/code_1"
app:layout_constraintStart_toEndOf="#id/code_1" />
<EditText
android:id="#+id/code_3"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:inputType="textCapCharacters"
android:maxLength="2"
android:text="C3"
android:textAlignment="center"
android:textSize="#dimen/text_big"
app:layout_constraintBottom_toBottomOf="#id/code_1"
app:layout_constraintStart_toEndOf="#id/code_2" />
<Button
android:id="#+id/button_a"
android:layout_width="#dimen/button_size"
android:layout_height="#dimen/button_size"
android:layout_marginTop="30dp"
android:text="A"
android:textSize="#dimen/text_big"
app:layout_constraintStart_toStartOf="#+id/code_1"
app:layout_constraintTop_toBottomOf="#+id/code_1" />
<Button
android:id="#+id/button_b"
android:layout_width="#dimen/button_size"
android:layout_height="#dimen/button_size"
android:text="B"
android:textSize="#dimen/text_big"
app:layout_constraintStart_toEndOf="#id/button_a"
app:layout_constraintBottom_toBottomOf="#id/button_a" />
<!--Button // This is what I want to achieve in code.
android:id="#+id/button_c"
android:layout_width="#dimen/button_size"
android:layout_height="#dimen/button_size"
android:text="C"
android:textSize="#dimen/text_big"
app:layout_constraintStart_toEndOf="#id/button_b"
app:layout_constraintBottom_toBottomOf="#id/button_a" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val buttonSize = resources.getDimension(R.dimen.button_size).toInt()
val textSize = resources.getDimension(R.dimen.text_big)
val layout = main_layout
var letter = 67
val buttonB = button_b
val button = Button(this)
val txt = letter.toChar().toString()
button.id = View.generateViewId()
button.text = "C"
button.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
button.width = 157 // or start with 400, then click on C will reduce size gradually
// button.setPadding(0,0,0,0)
button.height = buttonSize
button.gravity = Gravity.CENTER
// button.minWidth = 0 // will set button width to 231, regardless other settings
layout.addView(button)
button.setOnClickListener {
buttonB.width = buttonB.width + 10
label_enter_code.text = "W: ${button.width}, H: ${button.height}"
button.width = button.width - 10
// val marginLayoutParams = button.layoutParams as MarginLayoutParams
// marginLayoutParams.setMargins(0,0,0,0)
}
var constraintSet = ConstraintSet()
constraintSet.clone(layout)
constraintSet.connect(button.id, ConstraintSet.START, button_b.id, ConstraintSet.END )
constraintSet.connect(button.id, ConstraintSet.BOTTOM, button_a.id, ConstraintSet.BOTTOM)
constraintSet.applyTo(main_layout)
}
}
Solution:
Instead of button.width/height I use now:
button.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
button.layoutParams = ViewGroup.LayoutParams(buttonSize,buttonSize)
I did not do in first place, because val lp = button.layoutParams resulted in Null.
You should set layout parameters instead of width and height.
button.layoutParams = ViewGroup.LayoutParams(157, ViewGroup.LayoutParams.WRAP_CONTENT)
or equivalently when you are adding your view to the parent:
layout.addView(button, ViewGroup.LayoutParams(157, ViewGroup.LayoutParams.WRAP_CONTENT))
I'm facing a problem using a Samsung J1 device here.
But the image taken is bigger than the preview one.
This is the preview that I got:
and this is the final bitmap result:
I'm calling camera view with this attributes:
<com.otaliastudios.cameraview.CameraView
android:id="#+id/camera"
app:cameraGesturePinch="zoom"
app:cameraFlash="auto"
app:cameraAutoFocusResetDelay="0"
app:cameraGestureTap="focusWithMarker"
android:keepScreenOn="true"
app:cameraPreview="glSurface"
app:cameraPictureSizeSmallest="true"
android:adjustViewBounds="true"
app:cameraGestureScrollHorizontal="exposureCorrection"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
I already tried to use cameraPictureSizeAspectRatio with 4:3 but no success with it.
Did I do something wrong?
i have same problem .
after save image from cameraview ( i use camerakit lib) , display file by convert it to bitmap in imageview .
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
cameraKitView = findViewById(R.id.camera)
val captureButton = findViewById<View>(R.id.button_capture) as Button
val imageView = findViewById<ImageView>(R.id.myImageView)
captureButton.setOnClickListener {
cameraKitView!!.captureImage { _, capturedImage ->
val savedPhoto = getOutputMediaFile()
try {
val outputStream = FileOutputStream(savedPhoto!!.path)
outputStream.write(capturedImage)
outputStream.close()
val myBitmap = BitmapFactory.decodeFile(savedPhoto.getAbsolutePath())
imageView.setImageBitmap(myBitmap)
} catch (e: java.io.IOException) {
e.printStackTrace()
}
}
}
}
and this is my layout :
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.camerakit.CameraKitView
android:id="#+id/camera"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:adjustViewBounds="true"/>
<Button
android:id="#+id/button_capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="#string/save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="#+id/myImageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha="0.5"
android:adjustViewBounds="true"
android:background="#android:color/holo_blue_bright"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="#string/app_name" />
</android.support.constraint.ConstraintLayout>
but when show image and want to take another image, cameraview is not as scale as imageview
Solved :
just change scaleType to CentreCrop . that is it
I'm using ChatKit library (https://github.com/stfalcon-studio/ChatKit/) for a chat feature in my app.
In the message list provided by the library, I also included images messages.
It works fine, but the bubble's layout of the images is ambiguous, as the following picture :
Bubble picture 1 and 3 should be aligned on the right side, but they are stick on the left in the available space for incoming messages.
Note that the default text messages bubbles are displayed correctly on
the right.
I didn't find any attributes for the layout in the library to configure this behaviour.
This is my XML for the message list :
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_comments"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.stfalcon.chatkit.messages.MessagesList
android:id="#+id/messagesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/input_comment"
app:incomingDefaultBubbleColor="#color/lightGrayRetail"
app:incomingTimeTextColor="#color/white"
app:incomingDefaultBubblePressedColor="#color/lightGrayRetail"
app:incomingDefaultImageOverlayPressedColor="#color/lightGrayRetail"
app:outcomingDefaultBubblePressedColor="#color/pinkRetail"
app:outcomingDefaultImageOverlayPressedColor="#color/pinkRetail"
app:outcomingDefaultBubbleColor="#color/pinkRetail"
app:outcomingTimeTextColor="#color/colorMaterialGray" />
</android.support.v4.widget.SwipeRefreshLayout>
My incoming text message layout layout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<TextView
android:id="#+id/displayNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/bubble"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:textColor="#color/colorMaterialGray"/>
<de.hdodenhof.circleimageview.CircleImageView
android:id="#id/messageUserAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="8dp"
android:src="#drawable/woman" />
<ImageView
android:id="#+id/onlineIndicator"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_alignEnd="#id/messageUserAvatar"
android:layout_alignTop="#id/messageUserAvatar"
android:layout_marginEnd="5dp" />
<LinearLayout
android:id="#id/bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="30dp"
android:layout_below="#+id/displayNameTextView"
android:layout_toEndOf="#id/messageUserAvatar"
android:orientation="vertical">
<TextView
android:id="#id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:id="#+id/incomingTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#id/bubble"
android:layout_below="#id/bubble"
android:layout_marginEnd="4dp"
android:text="18:00"
android:layout_marginTop="4dp"
android:textColor="#color/colorMaterialGray" />
</RelativeLayout>
Outcoming layout :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<LinearLayout
android:id="#id/bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginStart="40dp"
android:orientation="vertical">
<TextView
android:id="#id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="#+id/outcomingTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/bubble"
android:layout_below="#id/bubble"
android:textColor="#color/colorMaterialGray"
android:layout_marginStart="16dp"/>
</RelativeLayout>
MessageHolder of outcoming :
public class CustomOutcomingMessageViewHolder extends MessageHolders.OutcomingTextMessageViewHolder<Comment> {
private TextView mOutcomingTimeTextView;
public CustomOutcomingMessageViewHolder(View itemView) {
super(itemView);
mOutcomingTimeTextView = itemView.findViewById(R.id.outcomingTimeTextView);
}
#Override
public void onBind(Comment comment) {
super.onBind(comment);
if(comment.getmContent() != null){
if(comment.getmContent().length() > 3){
SimpleDateFormat timeOutput = new SimpleDateFormat("HH:mm", Locale.FRANCE);
String commentPostedTime = timeOutput.format(comment.getmPostedDate());
mOutcomingTimeTextView.setText(commentPostedTime);
}
}
}
}
Any ideas ?
This happened to me without using any MessageHolder, I could fix it by assigning the same width to all images:
int width = Math.round( (float) getScreenWidthHeight().x * 0.8f); // width = 80% of screen's max width
int height = Math.round((float) bitmap.getHeight() / ((float) bitmap.getWidth() / (float) width));
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap), width, height, true);
where getScreenWidthHeight() is:
private Point getScreenWidthHeight(Activity activity) {
Display display = activity.getWindowManager(). getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
Did you check the sender ids in your code to be different for sender and receiver side by the id which is gotten from getId of message model? According to the library you need to determine the senderId in the Adapter initialization:
MessagesListAdapter<Message> adapter = new MessagesListAdapter<>(senderId,
imageLoader);
messagesList.setAdapter(adapter);
Library decides whether to align left or right according to senderIds comparison.
For anyone using the default MessagesListAdapter and ViewHolders, outgoing picture message ImageViews don't have their alignment set, but their parent view width is set to match_parent, which is why the image isn't aligned correctly.
item_outcoming_image_message.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp">
<com.stfalcon.chatkit.utils.RoundedImageView
android:id="#id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_marginLeft="#dimen/message_outcoming_bubble_margin_left"
android:layout_marginStart="#dimen/message_outcoming_bubble_margin_left" />
So, after looking through some of the library code, I found one solution is to simply override onBindViewHolder():
messagesAdapter = new MessagesListAdapter<Message>(senderId, imageLoader) {
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder.getItemViewType() == -132) { // -132 is an outgoing picture message
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.itemView.findViewById(com.stfalcon.chatkit.R.id.image).getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_END);
}
}
};
Fixed it by setting a fixed width using ConstraintLayout
val holdersConfig = MessageHolders()
.setIncomingTextConfig(
CustomIncomingTextMessageViewHolder::class.java,
R.layout.item_custom_incoming_text_message
)
Here is my item_custom_outcoming_image_message
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/imageMessageContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
tools:context=".chatting.ChattingFragment">
<com.stfalcon.chatkit.utils.RoundedImageView
android:id="#id/image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/ic_chat_pick_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent=".8"
tools:srcCompat="#tools:sample/backgrounds/scenic" />
<View
android:id="#id/imageOverlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/image"
app:layout_constraintEnd_toEndOf="#id/image"
app:layout_constraintStart_toStartOf="#id/image"
app:layout_constraintTop_toTopOf="#id/image"
tools:visibility="gone" />
<ImageView
android:id="#+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/image"
tools:src="#drawable/ic_message_status_processing" />
<TextView
android:id="#id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/status"
app:layout_constraintEnd_toStartOf="#+id/status"
app:layout_constraintTop_toTopOf="#id/status"
tools:text="12:15" />
</androidx.constraintlayout.widget.ConstraintLayout>