I'm currently facing 2 major problems,
I'm using a youtube player and when it gets on full screen, It plays for 1-2 seconds and stop.
When I click the "Play" button in the middle, it's buffering all over again. even if the gray bar filled to it's center.
those problems aren't occurring in portrait mode.
here is my class, like the youtube api demo with a bit defference
public class Video extends YouTubeFailureRecoveryActivity implements YouTubePlayer.OnFullscreenListener, Utils.OnGetUrlListener, View.OnClickListener {
static int AUTO_PLAY_DELAY = 1000;
static final int PORTRAIT_ORIENTATION = Build.VERSION.SDK_INT < 9
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
private LinearLayout mRootLayout;
/**
* * Youtube ***
*/
YouTubePlayerView mPlayerView;
YouTubePlayer mPlayer;
boolean mIsFullscreen;
String urlID;
/**
* * My ***
*/
RelativeLayout mContainer;
ImageView mBtPlay;
boolean mIsNeedSetFlags;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils.getInstance().setActivity(this);
setContentView(R.layout.video_main);
mIsNeedSetFlags = true;
mRootLayout = (LinearLayout) findViewById(R.id.video_root_layout);
mContainer = (RelativeLayout) findViewById(R.id.container);
mBtPlay = (ImageView) findViewById(R.id.video_play);
mBtPlay.setVisibility(View.INVISIBLE);
mPlayerView = (YouTubePlayerView) findViewById(R.id.player);
Intent intent = getIntent();
doLayout();
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
mPlayer = player;
player.addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT);
player.setOnFullscreenListener(this);
if (mIsNeedSetFlags) {
mIsNeedSetFlags = false;
int controlFlags = player.getFullscreenControlFlags();
setRequestedOrientation(PORTRAIT_ORIENTATION);
controlFlags |= YouTubePlayer.FULLSCREEN_FLAG_ALWAYS_FULLSCREEN_IN_LANDSCAPE;
player.setFullscreenControlFlags(controlFlags);
}
if (!wasRestored) {
player.cueVideo(urlID);
}
}
#Override
protected YouTubePlayer.Provider getYouTubePlayerProvider() {
return mPlayerView;
}
private void doLayout() {
LinearLayout.LayoutParams playerParams = (LinearLayout.LayoutParams) mPlayerView.getLayoutParams();
if (mIsFullscreen) {
playerParams.width = LinearLayout.LayoutParams.MATCH_PARENT;
playerParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
mParallaxScrollView.setVisibility(View.GONE);
} else {
mParallaxScrollView.setVisibility(View.VISIBLE);
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
ViewGroup.LayoutParams otherViewsParams = mParallaxScrollView.getLayoutParams();
playerParams.width = otherViewsParams.width = MATCH_PARENT;
playerParams.height = WRAP_CONTENT;
mRootLayout.setOrientation(LinearLayout.VERTICAL);
}
}
mPlayerView.setLayoutParams(playerParams);
}
#Override
public void onFullscreen(boolean isFullscreen) {
mIsFullscreen = isFullscreen;
showPlayerAndPlay();
doLayout();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
doLayout();
}
#Override
public void onGetUrlFinished(String videoUrl) {
urlID = videoUrl;
mBtPlay.setVisibility(View.VISIBLE);
mBtPlay.setOnClickListener(this);
mPlayerView.initialize(Utils.YOU_TUBE_DEV_KEY, this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.video_play:
showPlayerAndPlay();
break;
}
}
private void showPlayerAndPlay() {
mPlayerView.setVisibility(View.VISIBLE);
mBtPlay.setVisibility(View.INVISIBLE);
if (!mPlayer.isPlaying())
new android.os.Handler().postDelayed(new Runnable() {
#Override
public void run() {
mPlayer.play();
}
}, AUTO_PLAY_DELAY);
}
}
YouTube does not allow other views to be overlayed on top of its player view.
If you check the logs, you will also see a warning message that specifies this very limitation, plus more information on which view (its ID) and the overlapping region.
A good alternative is to used Exoplayer, to overlay your video with view. It is not part of the android sdk, but it's recommended by google and included in android developer documentation :
http://google.github.io/ExoPlayer/ https://developer.android.com/guide/topics/media/exoplayer.html
Exoplayer allow you to stream any kind of video, not only Youtubes videos.
It's also good to mention that Exoplayer is used in Youtube application.
As the answer marked as correct explained: the problem is overlaying a view over the Youtube player view. If you need to keep those views will the Youtube is initializing then this will do the trick.
I was doing a loading animation with crossfade for the involved views. Setting alpha to 0 won't fix the issue because the view is still there. But setting visibility to GONE or INVISIBLE does work. For what I understand a View is not computed if is not VISIBLE, well at least it will not be taken into consideration after the visibility changed. Finally, I did something like this:
myView.animate().alpha(0).setDuration(800).setListener(
new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
myView.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
}).start();
Related
After I close video fullscreen, I want webview to show it's last position, i.e, before going into full screen mode.
Right now it's going to the top of the page and I have to scroll down again to find the video.
here is my code:
private class ChromeClient extends WebChromeClient {
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private int mOriginalOrientation;
private int mOriginalSystemUiVisibility;
ChromeClient() {}
public Bitmap getDefaultVideoPoster()
{
if (mCustomView == null) {
return null;
}
return BitmapFactory.decodeResource(getApplicationContext().getResources(), 2130837573);
}
public void onHideCustomView()
{
((FrameLayout)getWindow().getDecorView()).removeView(this.mCustomView);
this.mCustomView = null;
getWindow().getDecorView().setSystemUiVisibility(this.mOriginalSystemUiVisibility);
setRequestedOrientation(this.mOriginalOrientation);
this.mCustomViewCallback.onCustomViewHidden();
this.mCustomViewCallback = null;
}
public void onShowCustomView(View paramView, WebChromeClient.CustomViewCallback paramCustomViewCallback)
{
if (this.mCustomView != null) {
onHideCustomView();
return;
}
this.mCustomView = paramView;
this.mOriginalSystemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
this.mOriginalOrientation = getRequestedOrientation();
this.mCustomViewCallback = paramCustomViewCallback;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
((FrameLayout)getWindow().getDecorView()).addView(this.mCustomView, new FrameLayout.LayoutParams(-1, -1));
getWindow().getDecorView().setSystemUiVisibility(3846 | SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
#Override
public void onConfigurationChanged(#NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
webview.saveState(outState);
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
webview.restoreState(savedInstanceState);
}
I can't understand why the webview is going back to the top again after I exit full screen.
Please help me to fix that.
Hi I think the code above needs only some line of code to fix that
Step 1
Declare a variable in your ChromeClient class.
int positionY;
Step 2
Now save the scroll position before going to fullscreen mode.
positionY = webView.getScrollY();
here I can see that you are going to fullscreen on onShowCustomView method so add this line under this method.
Step 3
Now restore the scroll position after coming back from fullscreen.
webView.postDelayed(new Runnable() {
#Override
public void run() {
webView.scrollTo(0, positionY);
}
// Delay the scrollTo to make it work
}, 300);
add this code under your onHideCustomView method.
That's it you are done with the coding run it and it will show the position correctly.
I want to implement YouTube Player View on my app, but since my app is an alarm clock, i don't want the user to be able to pause/stop the video or to change the volume. I tried to put a view on the YouTube Player View to block the clicks on it, but i guess that it's against the google policy because when i do that the video is not playing. I also tried:
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/ypvAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/half_activity_vertical_margin"
android:layout_marginBottom="#dimen/standard_button_size"
android:clickable="false" />
But it's not working. Is there something i can do?
With this solution, you can disable click events on a view and all its children by setting enable to false with view.setEnabled(false) for each child. Call it in onInitializationSuccess callback :
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer youTubePlayer, boolean b) {
enableDisableView(mYoutubeplayerView, false);
mPlayer = youTubePlayer;
mPlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL);
mPlayer.loadVideo("63kmMcHBQlA");
}
Here is a complete working example :
public class MainActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {
String mApiKey = "YOUR_API_KEY";
YouTubePlayerView mYoutubeplayerView;
YouTubePlayer mPlayer;
/**
* disable all click event : https://stackoverflow.com/a/19464718/2614364 by Parag Chauhan
*
* #param view
* #param enabled
*/
public static void enableDisableView(View view, boolean enabled) {
view.setEnabled(enabled);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int idx = 0; idx < group.getChildCount(); idx++) {
enableDisableView(group.getChildAt(idx), enabled);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mYoutubeplayerView = (YouTubePlayerView) findViewById(R.id.ypvAlert);
mYoutubeplayerView.initialize(mApiKey, this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer youTubePlayer, boolean b) {
enableDisableView(mYoutubeplayerView, false);
mPlayer = youTubePlayer;
mPlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL);
mPlayer.loadVideo("63kmMcHBQlA");
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult youTubeInitializationResult) {
}
#Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
if (resultCode == RESULT_OK) {
mPlayer.release();
}
}
}
just add this line
youTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL);
What i created while making CHROMELESS youtube player view is here. It is loading and playing perfectly but the buffering circle plays continuously even when video gets completed. Can anyone help me to remove buffering progress when it is not required and make a perfect youtube player?
MainActivity.java
package com.rocky.youtubedemo;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
public class MainActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {
private static final int RECOVERY_REQUEST = 1;
private static String YOUTUBE_API_KEY = "";
private YouTubePlayerView youTubeView;
private Context context;
private MyPlayerStateChangeListener playerStateChangeListener;
private MyPlaybackEventListener playbackEventListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
playerStateChangeListener = new MyPlayerStateChangeListener();
playbackEventListener = new MyPlaybackEventListener();
YOUTUBE_API_KEY = "PLACE_YOUR_API_KEY_HERE";
youTubeView = (YouTubePlayerView) findViewById(R.id.youtube_view);
youTubeView.initialize(YOUTUBE_API_KEY, this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, final YouTubePlayer player, boolean wasRestored) {
player.setPlayerStateChangeListener(playerStateChangeListener);
player.setPlaybackEventListener(playbackEventListener);
if (!wasRestored) {
player.loadVideo("fhWaJi1Hsfo"); // Plays https://www.youtube.com/watch?v=fhWaJi1Hsfo
player.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult errorReason) {
if (errorReason.isUserRecoverableError()) {
Toast.makeText(context, errorReason.toString(), Toast.LENGTH_LONG).show();
// errorReason.getErrorDialog(this, RECOVERY_REQUEST).show();
} else {
String error = errorReason.toString();
Toast.makeText(context, error, Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOVERY_REQUEST) {
// Retry initialization if user performed a recovery action
getYouTubePlayerProvider().initialize(YOUTUBE_API_KEY, this);
}
}
private void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
protected YouTubePlayer.Provider getYouTubePlayerProvider() {
return youTubeView;
}
private final class MyPlaybackEventListener implements YouTubePlayer.PlaybackEventListener {
#Override
public void onPlaying() {
// Called when playback starts, either due to user action or call to play().
showMessage("Playing");
}
#Override
public void onPaused() {
// Called when playback is paused, either due to user action or call to pause().
showMessage("Paused");
}
#Override
public void onStopped() {
// Called when playback stops for a reason other than being paused.
showMessage("Stopped");
}
#Override
public void onBuffering(boolean b) {
showMessage("buffer");
}
#Override
public void onSeekTo(int i) {
// Called when a jump in playback position occurs, either
// due to user scrubbing or call to seekRelativeMillis() or seekToMillis()
}
}
private final class MyPlayerStateChangeListener implements YouTubePlayer.PlayerStateChangeListener {
#Override
public void onLoading() {
showMessage("loading");
}
#Override
public void onLoaded(String s) {
showMessage("loaded");
}
#Override
public void onAdStarted() {
// Called when playback of an advertisement starts.
}
#Override
public void onVideoStarted() {
// Called when playback of the video starts.
showMessage("started");
}
#Override
public void onVideoEnded() {
// Called when the video reaches its end.
}
#Override
public void onError(YouTubePlayer.ErrorReason errorReason) {
// Called when an error occurs.
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/youtube_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
In your onInitializationSuccess(), set a PlaybackEventListener on the player. Override the onBuffering() and do something like this:
ViewGroup ytView = youTubeView; // if you are using YouTubePlayerView
ViewGroup ytView = (ViewGroup)ytPlayerFragment.getView(); // if you are using YouTubePlayerFragment
ProgressBar progressBar;
try {
// As of 2016-02-16, the ProgressBar is at position 0 -> 3 -> 2 in the view tree of the Youtube Player Fragment/View
ViewGroup child1 = (ViewGroup)ytView.getChildAt(0);
ViewGroup child2 = (ViewGroup)child1.getChildAt(3);
progressBar = (ProgressBar)child2.getChildAt(2);
} catch (Throwable t) {
// As its position may change, we fallback to looking for it
progressBar = findProgressBar(ytView);
// I recommend reporting this problem so that you can update the code in the try branch: direct access is more efficient than searching for it
}
int visibility = isBuffering ? View.VISIBLE : View.INVISIBLE;
if (progressBar != null) {
progressBar.setVisibility(visibility);
// Note that you could store the ProgressBar instance somewhere from here, and use that later instead of accessing it again.
}
Make method like this one:
private ProgressBar findProgressBar(View view) {
if (view instanceof ProgressBar) {
return (ProgressBar)view;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
ProgressBar res = findProgressBar(viewGroup.getChildAt(i));
if (res != null) return res;
}
}
return null
}
By this way you can enable progress when it is buffering and disable it when it is not.
I am successfully integrate YouTube Android Player API for my apps. I am curious to know about which file is rendered in the player. Every single video file may have several formats like 320dpi,720dpi & etc.
If my users, is in lower bandwidth; can i choose the file format or the API automatically detects which version would be played in that situation and vice-verse. My code:
public class YoutubeVideoActivity extends YouTubeBaseActivity implements
YouTubePlayer.OnInitializedListener, YouTubePlayer.OnFullscreenListener {
Activity activity = YoutubeVideoActivity.this;
public static final String API_KEY = "AIzaSyDN6Q9Pv4seQZqIcjB*********Po5k";
// public static final String VIDEO_ID = "psY0Botpi84";
public String new_id;
private boolean fullscreen;
private YouTubePlayerView playerView;
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_youtube_video);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Intent intent = getIntent();
String video_link = intent.getExtras().getString("video_link");
try {
new_id = video_link.substring("http://www.youtube.com/watch?v="
.length());
if (new_id.equals("")) {
IndepententTVUtils.showCustomAlert(activity,
"Data is not availble. Press back key",
R.drawable.ic_new_launcher);
} else {
playerView = (YouTubePlayerView) findViewById(R.id.youtubeplayerview);
playerView.initialize(API_KEY, this);
}
} catch (Exception e) {
IndepententTVUtils.showCustomAlert(activity,
"Data is not availble", R.drawable.ic_new_launcher);
}
}
#Override
public void onInitializationFailure(Provider arg0,
YouTubeInitializationResult arg1) {
Toast.makeText(getApplicationContext(),
"To See this Video, Install Latest YouTube Application",
Toast.LENGTH_LONG).show();
}
#Override
public void onInitializationSuccess(Provider arg0, YouTubePlayer player,
boolean wasRestored) {
player.setOnFullscreenListener(this);
if (!wasRestored && new_id != null) {
player.cueVideo(new_id);
}
}
#Override
public void onFullscreen(boolean isFullscreen) {
fullscreen = isFullscreen;
}
}
The player sets video quality automatically according to the users bandwidth or internet speed, if it was not so there would be an option specifying the setPlaybackQuality in player.
There are only restricted options to change the player settings that are
here
When the screen rotates my seekbar's colored bar goes back to its initial value, while the thumb remains at the correct position.
Basically from this:
It becomes like this:
Note that the TextView showing 15 is connected to the seekbar and correctly shows the same value, which is updated in onCreateView retrieving the value with getProgress on the seekbar, so the seekbar has the correct progress internally but "forgets" to update its bar. Note also that if moved slightly, the bar will be updated correctly.
The strange thing is that I have an identical seekbar, on which I do exactly the same actions(method calls etc) but this one never has this problem.
They are defined in the same way in the XML layout file(except for the id).
These seekbars are inside a Fragment shown into a ViewPager, here's more or less the code for the fragment:
public class NewCharacterNameFragment extends Fragment
implements NumericSeekBar.OnValueChangedListener {
private static final String LEVEL = "org.my.package.LEVEL";
private static final String STATS = "org.my.package.STATS";
private NumericSeekBar levelBar; // Causing problems
private NumericSeekBar statsBar; // Well behaved
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (savedInstanceState == null) { // defaults values to avoid multiple checks later
savedInstanceState = new Bundle();
savedInstanceState.putInt(LEVEL, 1);
savedInstanceState.putInt(STATS, 30);
}
View view = inflater.inflate(R.layout.new_character_name_fragment, container,
false);
levelBar = (NumericSeekBar) view.findViewById(R.id.levelSeekBar);
statsBar = (NumericSeekBar) view.findViewById(R.id.statPointsSeekBar);
levelBar.setValue(savedInstanceState.getInt(LEVEL));
levelBar.setMax(20);
levelBar.setValueChangedListener(this);
statsBar.setValue(savedInstanceState.getInt(STATS));
statsBar.setMax(100);
statsBar.setValueChangedListener(this);
// Initialize the text-views with the progress values:
TextView tView = (TextView) view.findViewById(R.id.statPointsNumTextView);
tView.setText(Integer.valueOf(statsBar.getValue()).toString());
tView = (TextView) view.findViewById(R.id.levelNumTextView);
tView.setText(Integer.valueOf(levelBar.getValue()).toString());
return view;
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(LEVEL, levelBar.getValue());
savedInstanceState.putInt(STATS, statsBar.getValue());
}
#Override
public void onNumericSeekBarValueChanged(NumericSeekBar bar, int value,
boolean fromUser) {
// Called whenever the seekbar value changes
if (bar == statsBar) {
TextView view = (TextView) getView().findViewById(R.id.statPointsNumTextView);
view.setText(Integer.valueOf(value).toString());
} else if (bar == levelBar) {
TextView view = (TextView) getView().findViewById(R.id.levelNumTextView);
view.setText(Integer.valueOf(value).toString());
}
}
}
Where NumericSeekBar is a widget I created and is basically a LinearLayout with the two increment and decrement buttons and the seekbar:
public class NumericSeekBar extends LinearLayout
implements SeekBar.OnSeekBarChangeListener, View.OnClickListener {
public interface OnValueChangedListener {
public void onNumericSeekBarValueChanged(NumericSeekBar bar, int value,
boolean fromUser);
}
private Button incButton;
private Button decButton;
private SeekBar seekBar;
private OnValueChangedListener listener = null;
private int maxValue = 100;
private int value = 0;
public NumericSeekBar(Context ctx) {
super(ctx);
setOpts();
setWidgets();
}
public NumericSeekBar(Context ctx, AttributeSet attributes) {
super(ctx, attributes);
setOpts();
setWidgets();
}
public void setValueChangedListener(OnValueChangedListener listener) {
this.listener = listener;
}
public void setMax(int maxValue) {
this.maxValue = maxValue;
seekBar.setMax(maxValue);
}
public int getValue() {
return this.value; // using seekBar.getProgress() obtains same results
}
public boolean setValue(int value) {
if (value < 0 || value > maxValue) {
return false;
}
this.value = value;
seekBar.setProgress(value);
return true;
}
#Override
public void onStopTrackingTouch(SeekBar bar) {
bar.setSecondaryProgress(bar.getProgress());
}
#Override
public void onStartTrackingTouch(SeekBar bar) {
}
#Override
public void onProgressChanged(SeekBar bar, int value, boolean fromUser) {
this.value = value;
if (listener != null ){
listener.onNumericSeekBarValueChanged(this, value, fromUser);
}
if (!fromUser) {
bar.setSecondaryProgress(0);
}
}
#Override
public void onClick(View v) {
// Handle increment/decrement button clicks
if (v.equals(incButton)) {
this.setValue(this.getValue() + 1);
} else if(v.equals(decButton)) {
this.setValue(this.getValue() - 1);
}
}
private void setOpts() {
setOrientation(HORIZONTAL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setShowDividers(SHOW_DIVIDER_NONE);
}
}
private void setWidgets() {
incButton = new Button(getContext());
decButton = new Button(getContext());
seekBar = new SeekBar(getContext());
incButton.setText("+");
incButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
incButton.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
(float) 0.4));
incButton.setOnClickListener(this);
decButton.setText("-");
decButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
decButton.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
(float) 0.4));
decButton.setOnClickListener(this);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
(float) 0.2);
layoutParams.gravity = Gravity.CENTER;
seekBar.setLayoutParams(layoutParams);
setMax(this.maxValue);
setValue(this.value);
addView(incButton);
addView(seekBar);
addView(decButton);
seekBar.setOnSeekBarChangeListener(this);
}
}
This happens both on the emulator and on a physical device.
EDIT: I just tested my app on an android 4 emulator and this does not happen, so it seems to be something 2.x related.
EDIT2: I've tried to invalidate() the bars in onCreateView, onStart and onResume but the problems still occurs. I've also tried to put a levelBar.setValue(levelBar.getValue()) in onResume but nothing changed.
I really don't understand what's happening.
EDIT3: I've added an other fragment which contains six of these bars and only the levelBar in the code above behaves strangely. I wonder how is this possible. Either there is some really strange bug, or I'm doing something not properly, even though I can't see where(and in android 4.x all works well).
EDIT4: My third edit is incorrect: now almost all the bars have this behaviour. The statsBar above seems to be the only one that is never affected.
I finally understood what's wrong with the code.
It seems like changing the maximum value of a SeekBar does not trigger a repaint of the color bar while it does trigger a repaint of the thumb. This is probably a bug in android 2.x(since it does not happen in android 4.x).
To solve this problem you simply have to set the maximum value before setting the progress on the seek-bar.
In my case only some bars were affected because I set the default maximum for the NumericSeekBar to 100, and only the bars with a different maximum where affected.
It's still not clear why invalidating the view in onResume does not produce the correct re-drawn of the widget.
I find the recurrence method:
final SeekBar seekBar = (SeekBar) findViewById(R.id.test_seekbar);
seekBar.setMax(4000);
seekBar.setProgress(1500);
new Thread(new Runnable() {
public void run() {
seekBar.setProgress(500);
}
}).start();
for (int i = 0; i < 5000; i++) {
seekBar.setProgress(2000);
}
above code, called ProgressBar#setProgress in work thread, it causes the bug.
Android official documentation advice called it at main thread, like this:
public class MyActivity extends Activity {
private static final int PROGRESS = 0x1;
private ProgressBar mProgress;
private int mProgressStatus = 0;
private Handler mHandler = new Handler();
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.progressbar_activity);
mProgress = (ProgressBar) findViewById(R.id.progress_bar);
// Start lengthy operation in a background thread
new Thread(new Runnable() {
public void run() {
while (mProgressStatus < 100) {
mProgressStatus = doWork();
// Update the progress bar
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
}
}
}).start();
}
}