I have a RecyclerView. You can scroll vertically and horizontally too.
Like this:
Check the item's width.
holder.itemView.post(new Runnable()
{
#Override
public void run()
{
int cellWidth = holder.itemView.getWidth();
}
});
The width is 5234.
When I want to scroll to the center.(I didn't calculate with device's screen's size, but this is not important now.) I call this:
recyclerView.smoothScrollBy((5234/2), 0)
It is work good on these emulators:
480x800 mdpi (API 24)
480x800 hdpi (API 24)
Isn't work good:
1080x1920 420dpi (API 21)
In 1080x1920. I the recycler width is 5234, when I call the smoothScrollBy with 5234/2 . Than It just go to ~1000. So can't jump to center.
Why? :/ The smoothScrollBy is waiting PX.
UPDATE:
If I use Handler with postDelay, then it works well. So maybe the scrolling is called soo fast. I trying to find better solution.
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
recyclerView.smoothScrollBy(5234/2, 0);
}
} ,1000);
I found the solution
ViewTreeObserver viewTreeObserver = this.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
recyclerView.smoothScrollBy(5234/2, 0);
}
});
Related
I am working on an Android application with an embedded QR code scanner using the Google Vision API. The scanner functions, but the SurfaceView that acts as camera preview is stretched vertically. The degree of distortion is different for different emulated devices.
As I understand it, you would use mCameraSource.setRequestedPreviewSize(w,h) to set the correct size. w and h I have set as Resources.getSystem().getDisplayMetrics().widthPixels and Resources.getSystem().getDisplayMetrics().heightPixels, respectively. However, I have noticed that regardless of what numbers I parse as width and height, there are no changes in the way it displays.
However, resizing the SurfaceView on which it is displayed does have an effect on the distortion. For one particular emulated Android device I can statically set the right width and height. For different devices, however, with a slightly different pixel w:h ratio, the distortion can become quite large.
I have read various solutions on StackOverflow, but most use the CameraPreview instead of the CameraSource.Builder.
My code thus far is (part of ScannerActivity.java):
private SurfaceView svCamera;
private BarcodeDetector barcodeDetector;
private CameraSource cameraSource;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scanner);
initViews();
initListeners();
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels)
.setAutoFocusEnabled(true)
.build();
svCamera.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
requestPermission();
try {
if (ActivityCompat.checkSelfPermission(ScannerActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
cameraSource.start(svCamera.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
scanned = true;
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
...
}
});
} }
Can someone help me with setting preview size?
The way I fixed it with help of Alex Cohn's answer:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
...
cameraSource.setRequestedPreviewSize(1280, 720); // Hardcoded, for now.
And I set the size of the SurfaceView with:
svCamera.setLayoutParams(new RelativeLayout.LayoutParams(width, width/9*16));
If I remember I will update this to a non-hardcoded version.
Quite contrary. You cannot choose arbitrary resolution for setRequestedPreviewSize(). This CameraSource API wraps the ordinary Camera API, which exposes only some, "supported" pairs of width and height.
If you want to display the live view undistorted, you must setup your SurfaceView to match the aspect ratio of chosen camera preview. This means, it's OK to use surface of 320x240 pixel for camera 640x480. It's even OK to use surface of 1280x720 for camera 1920x1080.
But if you have surface of 800x480 for camera of 1280x720 (and if your devices supports such camera resolution), the picture will be slightly stretched.
In my layout I have a GridView containing 4 custom ImageViews. I'm setting GridView's visibility to invisible until all ImageViews are resized at first but when the GridView is shown, there's a short blink with ImageViews still unchanged.
blink for a split second
views are resized in a moment
Each ImageView creates separate listener in order to scale its size:
//Setting new params as half of parent's size and increasing counter
if (getViewTreeObserver().isAlive()) {
final ViewTreeObserver viewTreeObserver = getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
View parent = (View) getParent();
int dimension = Math.min(parent.getWidth(), parent.getHeight()) / 2;
mThisImageView.setLayoutParams(new AbsListView.LayoutParams(dimension, dimension));
ResizeCounter.setCounter(ResizeCounter.getCounter() + 1);
return true;
}
});
}
//Activity listens to the moment when all ImageViews have been resized
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.setVisibility(View.VISIBLE);
}
}
});
I've also tried to resize them in onGlobalLayout method (same result) and to override onMeasure method (parent View is still null at this point).
I suspect that it's too late to change views in onPreDraw() but is there a method that can be called earlier inside which I can be sure that all views have been measured?
Try to call mAnswerGridView.requestLayout() before mAnswerGridView.setVisibility(View.VISIBLE);
This may not work because as it's stated at Android Developers
This will schedule a layout pass of the view tree.
So you may better force relayout:
relayoutChildren(View view) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); }
I've created a handler that schedules setting visibility right after calling requestLayout.
Works well in this case.
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.requestLayout();
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
mAnswerGridView.setVisibility(View.VISIBLE);
}
});
}
}
});
want to turn a card in my app. I have 2 ImageViews 1 Cardfront and 2 Cardback.
My theory ->
I change the width of the cardfront from 100% to 0%
I change the width of the cardback from 0% to 100%
I googled for solution on changing the width of am ImageView while runtime, but the solution I found don't work.
// Code for step 1
ViewGroup.LayoutParams params = ivBomb.getLayoutParams();
int width = params.width;
for (int i = 1; i<width; i++) {
params.width--;
ivBomb.setLayoutParams(params);
Thread.sleep(10); // To see the change
}
When I start it without the Thread.sleep(10);, it disappears instantly. But when I start it with the Thread.sleep(10);, it waits ~7s and then disappears instantly.
What am I doing wrong?
You can use animation to get the flip card effect. This card flip animation tutorial here is for a fragment, but you can use the same animations for your views like
Animation cardFlipRightOut = AnimationUtils.loadAnimation(this, R.anim.card_flip_right_out);
cardFlipRightOut.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
Animation cardFlipLeftIn = AnimationUtils.loadAnimation(this, R.anim.card_flip_left_in);
cardFrontView.startAnimation(cardFlipLeftIn);
}
});
cardBackView.startAnimation(cardFlipRightIn);
Try calling one of these after setLayoutParams() :
1. requestLayout()
2. invalidate()
Since, requestLayout() should be called, when view's position or bounds in the parent layout have been changed, while invalidate() should be called when view's appearance has been changed. When you call requestLayout() then onLayout() and onMeasure() methods of the view will be fired, on the other hand when you call invalidate(), then onDraw() method will be fired.
I need to get the height of my web view so I can programatically work out the top margin. I'm using the AddOnPreDraw method which works fine on phones, but as soon as I use it on a tablet it returns null.
ViewTreeObserver viewTreeObserver = topContent.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int height = topContent.getMeasuredHeight();
if (height != 0) {
Log.d("Web View Height", "Continue Height: " + height);
RelativeLayout instructions = (RelativeLayout) findViewById(R.id.info_layout);
instructions.post(mAddTabletMargin);
}
topContent.getViewTreeObserver().removeOnPreDrawListener(
this);
return false;
}
});
So quesiton one is why does it work on phones but not tablets?
and question 2 is there any other methods I could use to get the height of the webvie wonce it's been drawn?
Thanks in advance.
Here is a simple way to perform this.
webView.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
webView.getHeight();
}
});
I'm trying to get my textView to react to a user's tap.
I found out that I actually have to set android:clickable="true", so my function is actually called now.
But my problem is, that I'm using an animation to move my textView within my activity (from bottom to top). So now the onClick function is only called when you tap where my textView used to be, not where it actually is.
How do you fix this?
EDIT:
Unfortunately, I wasn't able to move the actual TextView programmatically (I'm using a RelativeLayout) like the first answer suggests.
However, I could overlay the position of my TextView with another TextView (transparent) that's clickable only when the animation comes to an end.
Works perfectly.
When you are doing animations the TextView is only visualy moved (the graphic rendering representation is only moved on the screen) but the real TextView object stays on the old position. You have to manually (programatically) move the TextView to the new position.
Take a look at this presentation from Romain Guy and Chet Haase.
Chet Haase is taking about this issue at the 42:00 min. Take a look at the whole presentation if you have time. They are talking about some really usefull things.
I recently had to do this. You didn't provide any code, so this will have to do. The key is setting bottomMargins to compensate.
Animation yourAnimation = AnimationUtils.loadAnimation(getActivity().getApplicationContext(), R.anim.your_anim_file);
slideOutBottom.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
animatedButton.clearAnimation();
Resources r = view.getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, -68, r.getDisplayMetrics());
lp = (LinearLayout.LayoutParams) animatedButton.getLayoutParams();
lp.bottomMargin = -50;
cartFunctionButtons.setLayoutParams(lp);
}
});
yourAnimation.setFillAfter(true);
animatedButton.startAnimation(yourAnimation);