I am new to android. I implemented a GIF in my activity.
I found a way to make it loop only once. So far everything is fine but I would like to display the image of this gif at the end of the animation of this one, this time in image and not in gif. Basically I would like the gif to loop once and then become an image again
I implemented this on my build.gradle :
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
After that I set up my imageView :
<ImageView
android:id="#+id/fuse"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_4sdp"
android:layout_marginLeft="#dimen/_4sdp"
android:padding="#dimen/_8sdp"
android:src="#drawable/fuseev4"
tools:ignore="InvalidId" />
Now this is my java file to loop once:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityChatRoomBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
imageView = binding.fuse;
try {
setListeners();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void setListeners() throws InterruptedException {
binding.LayoutSend.setOnClickListener(view -> {
try {
Glide.with(this)
.asGif()
.load(R.drawable.fuseev4) //Your gif resource
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
.listener(new RequestListener<GifDrawable>() {
#Override
public boolean onLoadFailed(#Nullable #org.jetbrains.annotations.Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
resource.setLoopCount(1);
return false;
}
})
.into(imageView);
}
catch (Exception e){
System.out.println(e);
}
afterListeners();
});
}
public void afterListeners(){
Glide.with(this)
.asBitmap()
.load(R.drawable.fuseev4)
.into(imageView);
}
I couldn't find a way to solve my problem.
Thanks in advance for your help !
Try this in your onResourceReady() callback:
resource.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
#Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
// your code here
}});
1)as i read you are using bumptech.glide liabrary so try code like below,
private val image = "abc.png"
Glide.with(this).load(image).placeholder(R.drawable.placeholder) .into(binding.imageView); //here loading gif
comment if any query
Related
So, I have an activity, lets say a PetDetailActivity that shows a carousel with some Bitmaps in it (I use com.synnapps:carouselview:0.1.5 to handle my carousel). The problem is that the PetDetailActivity loaded with 0 sized carousel, which maybe the images is still being processed by a thread. How to wait Picasso to finish processing URLs, and then show it up in the new Activity?
This is the code of PetDetailActivity:
import ...
public class PetDetailActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pet_detail);
Intent i = getIntent();
Pet targetPet = (Pet)i.getSerializableExtra("PetObject");
ActionBar actionBar = getSupportActionBar();
if(actionBar!=null) actionBar.setDisplayHomeAsUpEnabled(true);
//Creating a BitmapHandler object to download image from URL to Bitmap object using picasso.
BitmapHandler bitmapHandler = new BitmapHandler(targetPet.getCarouselImageUrl());
final ArrayList<Bitmap> petCarouselBitmaps = bitmapHandler.getProcessedBitmap();
//The bitmap is being downloaded in other thread, so the activity is up and
//CarouselView is still empty (petCarouselBitmaps.size() == 0)
//So how to wait the bitmaps is processed, like show a loading screen on the UI?
CarouselView petCarousel = findViewById(R.id.petCarousel);
petCarousel.setPageCount(petCarouselBitmaps.size());
petCarousel.setImageListener(new ImageListener() {
#Override
public void setImageForPosition(int position, ImageView imageView) {
imageView.setImageBitmap(petCarouselBitmaps.get(position));
}
});
}
...
}
And Here is the BitmapHandler Class that downloads image from URL to a Bitmap using picasso:
public class BitmapHandler extends Thread {
ArrayList<String> urlList;
private ArrayList<Bitmap> loadedBitmap;
public BitmapHandler(ArrayList<String> list){
this.urlList = list;
this.loadedBitmap = new ArrayList<>();
}
public ArrayList<Bitmap> getProcessedBitmap(){
this.run();
//Returning the loaded bitmap as a ArrayList<Bitmap> Object.
return loadedBitmap;
}
#Override
public void run() {
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
loadedBitmap.add(bitmap);
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
for (String url : urlList) {
Picasso.get().load(url).into(target);
}
}
}
Thank you for any helps!
Problem: . How to wait Picasso to finish processing URLs
Solution:
I think you can go with Target callback:
private Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
}
#Override
public void onBitmapFailed() {
}
}
And while loading image, you need to write:
Picasso.with(this).load(myURL).into(target);
Just for the information:
onBitmapLoaded() mostly used to perform image operations before we load into the view actually.
Picasso.LoadedFrom describes where the image was loaded from, whether it's MEMORY, DISK or NETWORK.
I think you can use placeholder & then the image is loaded it will show in Image View.
And if you want to delay use can use Thread.sleep(5000).
Need help to resolve a Fotoapparat library issue.
io.fotoapparat.exception.camera.CameraException: Failed to open camera with lens position: io.fotoapparat.characteristic.LensPosition$Back#31c3b8a2 and id: 0
When I open the first time It will work correctly. But after that, I click on other tabs and then open camera screen It will display a blank white screen. I am using viewPager for that.
How did you initialize FA?
mCameraView = view.findViewById(R.id.camera);
fotoapparat = Fotoapparat.with(getActivity())
.into(mCameraView)
.previewScaleType(ScaleType.CenterCrop)
.logger(new Logger() {
#Override
public void log(String s) {
Log.e("Camera", s);
}
#Override
public void recordMethod() {
}
})
.cameraErrorCallback(new CameraErrorListener() {
#Override
public void onError(CameraException e) {
e.printStackTrace();
fotoapparat.stop();
}
})
.build();
FA version: 2.5.0
Devices/APIs affected: 19,20,21,22
I have made an imageView animate from one side to the other side of the screen. Here is the java code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageView = findViewById(R.id.imageView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
handleAnimation(imageView);
}
});
}
public void handleAnimation(View view) {
ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "x", 1000f);
animatorX.setDuration(2000);
animatorX.start();
}
}
And this is what we see when user clicks on the ANIMATE button:
Now my question is that how I can make a video file by capturing the animated imageView ?
EDIT:
What I need is: I want to make an app which takes some photos from the user and make some animations on the photos and some effects and also mix them with a desired sound and at the end exports a video clip. And of course if I can I would rather make all these things hidden.
You have to record your screen and then crop the video using your view's xy coordinates. You can record your screen using the MediaProject API on android (5) and above.
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;
private MediaProjection mMediaProjection;
private MediaProjectionCallback callback;
MediaProjectionManager projectionManager = (MediaProjectionManager)
context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
mMediaProjection.registerCallback(callback, null);
initRecorder();
mMediaRecorder.prepare();
mVirtualDisplay = createVirtualDisplay();
mMediaRecorder.start();
public void initRecorder() {
path = "/sdcard/Record/video" + ".mp4";
recId = "capture-" + System.currentTimeMillis() + ".mp4";
File myDirectory = new File(Environment.getExternalStorageDirectory(), "Record");
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncodingBitRate(MainFragment.bitRate);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(MainFragment.DISPLAY_WIDTH,
MainFragment.DISPLAY_HEIGHT);
mMediaRecorder.setOutputFile(path);
}
private VirtualDisplay createVirtualDisplay() {
return mMediaProjection.createVirtualDisplay("MainActivity",
MainFragment.DISPLAY_WIDTH, MainFragment.DISPLAY_HEIGHT, MainFragment.screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}
public class MediaProjectionCallback extends MediaProjection.Callback {
#Override
public void onStop() {
mMediaRecorder.stop();
// mMediaRecorder.reset();
mMediaRecorder.release();
mMediaProjection.unregisterCallback(callback);
mMediaProjection = null;
mMediaRecorder = null;
}
Once done simply call mMediaProjection.stop() to finish the recording and save the video as tmp
After which you can crop the video at the xy coordinates that your view is position using FFmpeg
ffmpeg -i in.mp4 -filter:v "crop=out_w:out_h:x:y" out.mp4
Where the options are as follows:
out_w is the width of the output rectangle
out_h is the height of the output rectangle
x and y specify the top left corner of the output rectangle
so in your case
String cmd ="-i '"+ tmpVideoPath+"' -filter:v "+"'crop="+view.getWidth()+":"+view.getHeight()+":"+view.getX()+":"+view.getY()+"'"+" -c:a copy "+outVideoPath
FFmpeg ffmpeg = FFmpeg.getInstance(context);
// to execute "ffmpeg -version" command you just need to pass "-version"
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {}
#Override
public void onProgress(String message) {}
#Override
public void onFailure(String message) {}
#Override
public void onSuccess(String message) {}
#Override
public void onFinish() {}
});
There are two possible approaches to archive this.
1- You can acchive this by using the javacv library (FFmpeg) to combine a set of bitmaps taken from the view
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("/sdcard/test.mp4",256,256);
try {
recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
recorder.setFormat("mp4");
recorder.setFrameRate(30);
recorder.setPixelFormat(avutil.PIX_FMT_YUV420P10);
recorder.setVideoBitrate(1200);
recorder.startUnsafe();
for (int i=0;i< 5;i++)
{
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
view.setDrawingCacheEnabled(false);
recorder.record(bitmap);
}
recorder.stop();
}
catch (Exception e){
e.printStackTrace();
}
all the code of using this library is here
2- You can use this link for record the screen and use as per your need.
Screen Recorder
Basically, what I want to do is to create Aztec code reader plugin.
So I need to open some kind of camera screen inside my app. I should do that inside my Java code, which right now looks like so:
public class AztecReaderPlugin extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
try {
if(action.equals("open")) {
Context context = cordova.getActivity().getApplicationContext();
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
callbackContext.success();
return true;
}
callbackContext.error("Something gone wrong!");
return false;
} catch (Exception e) {
callbackContext.error(e.getMessage());
return false;
}
}
}
It basically should execute the code inside MainActivity class. And the MainActivity class method onCreate looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
Button btnDoFocus = (Button)findViewById(R.id.buttonAutoFocus);
btnDoFocus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
preview.autoFocus();
}
});
Button btnDoAztec = (Button)findViewById(R.id.buttonDoAztec);
btnDoAztec.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
preview.setEnableReadAztecCode(true);
}
});
}
The thing is, when I did forget about AztecReaderPlugin, and run the MainActivity code as an standalone Android app, it works just like I would want.
I can't find any tutorial/post that would help me with my problem, and I don't have time to learn Android developing.
So my question is: How can I include that Aztec Code Reader inside my Cordova App?
// EDIT
I can Include my Plugin into App, the problem lays inside AztecReaderPlugin class and some Activity-related method. My problem is I can't open some kind of camera view through cordova. And that Camera view is my Plugin.
Sure you can
Firstly you need to declare your custom plugin in config.xml. You can found this file in res > xml folder.
<feature name="CustomPlugin">
<param name="android-package" value="com.Phonegap.CustomPlugin" />
</feature>
Then you need to implement plugin by using Java- code
public class CustomPlugin extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
throws JSONException {
if (action.equals("sayHello")){
try {
String responseText = "Hello world, " + args.getString(0);
callbackContext.success(responseText);
} catch (JSONException e){
callbackContext.error("Failed to parse parameters");
}
return true;
}
return false;
}
}
Finally we calling a plugin from javascript
function initial(){
var name = $("#NameInput").val();
cordova.exec(sayHelloSuccess, sayHelloFailure, "CustomPlugin", "sayHello", [name]);
}
function sayHelloSuccess(data){
alert("OK: " + data);
}
function sayHelloFailure(data){
alert("FAIL: " + data);
}
I'm using 3 Fragments inside a Viewpager, the problem is that I am loading big data in an Asynctask and loaders. On devices like HTC one, it works fine, however, on low-end devices, it takes a lot of time. This is mainly because when I implement the pagerAdapter, I put the Fragments inside an ArrayList, this force the fragments instantiate when the main activity is loaded. What I need is that it just "load" the first fragment (main) and when the user Swype, load the other fragment. its any way to achieve this? this is my pageAdapater
public class PagerAdapter extends FragmentPagerAdapter {
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
// private final ArrayList<String> titulos = new ArrayList<String>();
// private int NUM_PAGES =0;
public PagerAdapter(FragmentManager manager,int num_pages) {
super(manager);
// this.NUM_PAGES = num_pages;
}
public void addFragment(Fragment fragment,String title) {
mFragments.add(fragment);
notifyDataSetChanged();
}
#Override
public int getCount() {
//return NUM_PAGES;
return mFragments.size();
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
}
The above method from Sun did not work for me (maybe it does for you), but I thought I would share my edit of his method also. Very good method by the way Sun!
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(true);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (isFragmentVisible_ && !_hasLoadedOnce) {
new NetCheck().execute();
_hasLoadedOnce = true;
}
}
}
I'm gonna add my solution here since I faced a similar issue. My asynchronous task wasn't loading huge amounts of data, but it prevents unnecessary network calls. Here's what I added in my Fragment:
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (!isFragmentVisible_ && !_hasLoadedOnce) {
//run your async task here since the user has just focused on your fragment
_hasLoadedOnce = true;
}
}
}
With the above code, your Fragment will be loaded, but your async task will not run until the user actually scrolls to the Fragment for the first time. Once displayed, your async task will run for the first time automatically. Then you can provide a way to load more data via a button or pull to refresh. The above Fragment was in my ViewPager and seemed to work fine.
Slightly modified version to fix potential NPE caused by some views not fully initialised
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (!isFragmentVisible_ && !_hasLoadedOnce) {
new Handler().post(() -> {
makeAsyncRequest();//do your asyn stuffs
_hasLoadedOnce = true;
});
}
}
}
Use fragmentStatePageAdapter if you have a lot of pages and you want to destroy them when not visible.
It has implemented a setMenuVisibility(boolean menuVisible) when fragment becomes visible, so use that.
I might be late for the party but here's my solution and it works as expected. In all of your child fragments create a boolean variable:
private boolean loadFragmentExecuted = false;
in the child fragments create a generic method called loadFragment and move all of the logic you added in onCreateView to that method:
public void loadFragment()
{
if(!loadFragmentExecuted)
{
//Add your logic to manipulate the UI or load data etc...
loadFragmentExecuted = true;
}
}
in your pageview logic create the fragments dynamically like:
//add the fragment
String fragmentName = "com.something." + fragmentId;
//check if the class exists
try
{
Class myFragmentClass = Class.forName(fragmentName);
Fragment myFragment = (Fragment) myFragmentClass.newInstance();
mFragments.add(myFragment);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
then set your pager adapter and attach a tablayout with it:
//set our pager adapter that contains different fragments
mPagerAdapter = new BasePagerAdapter(mFragmentManager, mFragments);
//link the adapter to the viewpager
mViewPager.setAdapter(mPagerAdapter);
//cache fragments
int limit = (mPagerAdapter.getCount() > 0 ? mPagerAdapter.getCount() : 1);
mViewPager.setOffscreenPageLimit(limit);
//add the page listner to the viewPager and link it to the tabLayout
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
//on tab selected select current viewpager item
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
{
#Override
public void onTabSelected(TabLayout.Tab tab)
{
mViewPager.setCurrentItem(tab.getPosition());
//get fragment for the selected tab
Fragment f = mPagerAdapter.getItem(tab.getPosition());
//load the content of the fragment
try
{
Class c = f.getClass();
Method loadFragment = c.getMethod("loadFragment");
loadFragment.invoke(f);
}
catch (IllegalAccessException e){}
catch (InvocationTargetException e){}
catch (NoSuchMethodException e){}
}
#Override
public void onTabUnselected(TabLayout.Tab tab)
{
}
#Override
public void onTabReselected(TabLayout.Tab tab)
{
}
});