JiaoZiVideoPlayer使用说明(持续更新中

创建一个类继承JzvdStd并在XML设置
public class JzvdStdVolumeAfterFullscreen extends JzvdStd {
public JzvdStdVolumeAfterFullscreen(Context context) {
super(context);
}

public JzvdStdVolumeAfterFullscreen(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onPrepared() {
super.onPrepared();
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);
} else {
JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);
}
}

/**

  • 进入全屏模式的时候关闭静音模式
    */
    @Override
    public void startWindowFullscreen() {
    super.startWindowFullscreen();
    JZMediaManager.instanc​
    e().jzMediaInterface.setVolume(1f, 1f);
    }

/**

  • 退出全屏模式的时候开启静音模式
    */
    @Override
    public void playOnThisJzvd() {
    super.playOnThisJzvd();
    JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);
    }
    }

全屏状态播放完成,不退出全屏

创建一个类继承JzvdStd并在XML设置
public class JzvdStdAutoCompleteAfterFullscreen extends JzvdStd {
public JzvdStdAutoCompleteAfterFullscreen(Context context) {
super(context);
}

public JzvdStdAutoCompleteAfterFullscreen(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void startVideo() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
Log.d(TAG, “startVideo [” + this.hashCode() + "] ");
initTextureView();
addTextureView();
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

JZMediaManager.setDataSource(jzDataSource);
JZMediaManager.instance().positionInList = positionInList;
onStatePreparing();
} else {
super.startVideo();
}
}

@Override
public void onAutoCompletion() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
onStateAutoComplete();
} else {
super.onAutoCompletion();
}

}
}

全屏模式下显示分享按钮

复制DEMO下的layout文件在 layout_top 布局下 添加你的分享按钮
public class JzvdStdShowShareButtonAfterFullscreen extends JzvdStd {

public ImageView shareButton;

public JzvdStdShowShareButtonAfterFullscreen(Context context) {
super(context);
}

public JzvdStdShowShareButtonAfterFullscreen(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void init(Context context) {
super.init(context);
shareButton = findViewById(R.id.share);
shareButton.setOnClickListener(this);

}

@Override
public int getLayoutId() {
return R.layout.layout_standard_with_share_button;
}

@Override
public void onClick(View v) {
super.onClick(v);
if (v.getId() == R.id.share) {
Toast.makeText(getContext(), “Whatever the icon means”, Toast.LENGTH_SHORT).show();
}
}

@Override
public void setUp(JZDataSource jzDataSource, int screen) {
super.setUp(jzDataSource, screen);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
shareButton.setVisibility(View.VISIBLE);
} else {
shareButton.setVisibility(View.INVISIBLE);
}
}
}

小屏状态下不显示标题,全屏模式下显示标题

public class JzvdStdShowTitleAfterFullscreen extends JzvdStd {
public JzvdStdShowTitleAfterFullscreen(Context context) {
super(context);
}

public JzvdStdShowTitleAfterFullscreen(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void setUp(JZDataSource jzDataSource, int screen) {
super.setUp(jzDataSource, screen);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
titleTextView.setVisibility(View.VISIBLE);
} else {
titleTextView.setVisibility(View.INVISIBLE);
}
}
}

播放MP3

public class JzvdStdMp3 extends JzvdStd {

public JzvdStdMp3(Context context) {
super(context);
}

public JzvdStdMp3(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public int getLayoutId() {
return R.layout.jz_layout_standard_mp3;
}

@Override
public void onClick(View v) {
if (v.getId() == cn.jzvd.R.id.thumb &&
(currentState == CURRENT_STATE_PLAYING ||
currentState == CURRENT_STATE_PAUSE)) {
onClickUiToggle();
} else if (v.getId() == R.id.fullscreen) {

} else {
super.onClick(v);
}
}

//changeUiTo 真能能修改ui的方法
@Override
public void changeUiToNormal() {
super.changeUiToNormal();
}

@Override
public void changeUiToPreparing() {
super.changeUiToPreparing();
}

@Override
public void changeUiToPlayingShow() {
super.changeUiToPlayingShow();
thumbImageView.setVisibility(View.VISIBLE);

}

@Override
public void changeUiToPlayingClear() {
super.changeUiToPlayingClear();
thumbImageView.setVisibility(View.VISIBLE);

}

@Override
public void changeUiToPauseShow() {
super.changeUiToPauseShow();
thumbImageView.setVisibility(View.VISIBLE);

}

@Override
public void changeUiToPauseClear() {
super.changeUiToPauseClear();
thumbImageView.setVisibility(View.VISIBLE);

}

@Override
public void changeUiToComplete() {
super.changeUiToComplete();
}

@Override
public void changeUiToError() {
super.changeUiToError();
}
}

jzvdStdMp3 = findViewById(R.id.jz_videoplayer_mp3);
jzvdStdMp3.setUp(URL, “饺子摇摆”, Jzvd.SCREEN_WINDOW_NORMAL);
Glide.with(this)
.load(VideoConstant.videoThumbs[0][1])
.into(jzvdStdMp3.thumbImageView);

播放完成不显示预览图

public class JzvdStdShowTextureViewAfterAutoComplete extends JzvdStd {
public JzvdStdShowTextureViewAfterAutoComplete(Context context) {
super(context);
}

public JzvdStdShowTextureViewAfterAutoComplete(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onAutoCompletion() {
super.onAutoCompletion();
thumbImageView.setVisibility(View.GONE);
}

}

Home键退出界面暂停播放,返回界面继续播放

@Override
protected void onResume() {
super.onResume();
//home back
JzvdStd.goOnPlayOnResume();
}

@Override
protected void onPause() {
super.onPause();
// Jzvd.clearSavedProgress(this, null);
//home back
JzvdStd.goOnPlayOnPause();
}

边播边缓存和清晰度切换

  1. 集成videocache implementation ‘com.danikula:videocache:2.7.0’,并初始化
    public class ApplicationDemo extends Application {

@Override
public void onCreate() {
super.onCreate();
// LeakCanary.install(this);
}

private HttpProxyCacheServer proxy;

public static HttpProxyCacheServer getProxy(Context context) {
ApplicationDemo app = (ApplicationDemo) context.getApplicationContext();
return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
}

private HttpProxyCacheServer newProxy() {
return new HttpProxyCacheServer(this);
}
}
2.引用
LinkedHashMap map = new LinkedHashMap();

String proxyUrl = ApplicationDemo.getProxy(this).getProxyUrl(VideoConstant.videoUrls[0][9]);

map.put(“高清”, proxyUrl);
map.put(“标清”, VideoConstant.videoUrls[0][6]);
map.put(“普清”, VideoConstant.videoUrlList[0]);
JZDataSource jzDataSource = new JZDataSource(map, “饺子不信”);
jzDataSource.looping = true;
jzDataSource.currentUrlIndex = 2;
jzDataSource.headerMap.put(“key”, “value”);//header
mJzvdStd.setUp(jzDataSource
, JzvdStd.SCREEN_WINDOW_NORMAL);
Glide.with(this).load(VideoConstant.videoThumbList[0]).into(mJzvdStd.thumbImageView);

重复播放

创建一个类集成JzvdStd并在XML设置
public class JZVideoPlayerStandardLoopVideo extends JzvdStd{
public JZVideoPlayerStandardLoopVideo (Context context) {
super(context);
}

public JZVideoPlayerStandardLoopVideo (Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onAutoCompletion() {
super.onAutoCompletion();
startVideo();
}
}
还有一种方法就是上面清晰度切换loop循环标志

重力感应自动进入全屏

SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Jzvd.JZAutoFullscreenListener mSensorEventListener = new Jzvd.JZAutoFullscreenListener();
@Override
protected void onResume() {
super.onResume();
Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(mSensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(mSensorEventListener);
}

重力感应

Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
两个变量控制全屏前后的屏幕方向

不保存播放进度

Jzvd.SAVE_PROGRESS = false;

取消播放时在非WIFIDialog提示

Jzvd.WIFI_TIP_DIALOG_SHOWED=true;

清除某个URL进度

Jzvd.clearSavedProgress(this, “url”);

切换播放内核

ijk
复制Demo中JZMediaIjkplayer类到你的项目下
implementation ‘tv.danmaku.ijk.media:ijkplayer-java:0.8.4’
implementation ‘tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4’
Jzvd.setMediaInterface(new JZMediaIjkplayer()); // ijkMediaPlayer
Mediaplayer
Jzvd.setMediaInterface(new JZMediaSystem()); //
exo
复制Demo中JZExoPlayer类到你的项目下
implementation ‘com.google.android.exoplayer:exoplayer:2.7.1’
Jzvd.setMediaInterface(new JZExoPlayer()); //exo

用户埋点统计

Jzvd.setJzUserAction(new MyUserActionStd());
/**

  • 这只是给埋点统计用户数据用的,不能写和播放相关的逻辑,监听事件请参考MyJzvdStd,复写函数取得相应事件
    */
    class MyUserActionStd implements JZUserActionStd {

@Override
public void onEvent(int type, Object url, int screen, Object… objects) {
switch (type) {
case JZUserAction.ON_CLICK_START_ICON:
Log.i(“USER_EVENT”, “ON_CLICK_START_ICON” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_START_ERROR:
Log.i(“USER_EVENT”, “ON_CLICK_START_ERROR” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_START_AUTO_COMPLETE:
Log.i(“USER_EVENT”, “ON_CLICK_START_AUTO_COMPLETE” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_PAUSE:
Log.i(“USER_EVENT”, “ON_CLICK_PAUSE” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_CLICK_RESUME:
Log.i(“USER_EVENT”, “ON_CLICK_RESUME” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_SEEK_POSITION:
Log.i(“USER_EVENT”, “ON_SEEK_POSITION” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_AUTO_COMPLETE:
Log.i(“USER_EVENT”, “ON_AUTO_COMPLETE” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_ENTER_FULLSCREEN:
Log.i(“USER_EVENT”, “ON_ENTER_FULLSCREEN” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_QUIT_FULLSCREEN:
Log.i(“USER_EVENT”, “ON_QUIT_FULLSCREEN” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_ENTER_TINYSCREEN:
Log.i(“USER_EVENT”, “ON_ENTER_TINYSCREEN” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_QUIT_TINYSCREEN:
Log.i(“USER_EVENT”, “ON_QUIT_TINYSCREEN” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME:
Log.i(“USER_EVENT”, “ON_TOUCH_SCREEN_SEEK_VOLUME” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserAction.ON_TOUCH_SCREEN_SEEK_POSITION:
Log.i(“USER_EVENT”, “ON_TOUCH_SCREEN_SEEK_POSITION” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;

case JZUserActionStd.ON_CLICK_START_THUMB:
Log.i(“USER_EVENT”, “ON_CLICK_START_THUMB” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
case JZUserActionStd.ON_CLICK_BLANK:
Log.i(“USER_EVENT”, “ON_CLICK_BLANK” + " title is : " + (objects.length == 0 ? “” : objects[0]) + " url is : " + url + " screen is : " + screen);
break;
default:
Log.i(“USER_EVENT”, “unknow”);
break;
}
}
}

##相关函数回调,屏幕状态,播放器状态,事件 #####继承JzvdStd之后,可以通过父类的mCurrentState,取得当前的播放状态。

  • CURRENT_STATE_IDLE 未知状态,指控件被new出来之后什么都没做
  • CURRENT_STATE_NORMAL 普通状态
  • CURRENT_STATE_PREPARING 视频准备状态
  • CURRENT_STATE_PREPARING_CHANGING_URL 播放中切换url的准备状态
  • CURRENT_STATE_PLAYING 播放中状态
  • CURRENT_STATE_PAUSE 暂停状态
  • CURRENT_STATE_AUTO_COMPLETE 自动播放完成状态
  • CURRENT_STATE_ERROR 错误状态

复写进入播放状态的函数,取得播放状态的回调

  • onStateNormal 进入普通状态,通常指setUp之后
  • onStatePreparing 进入准备中状态,就是loading状态
  • onStatePlaying 进入播放状态
  • onStatePause 进入暂停状态
  • onStateError 进入错误状态
  • onStateAutoComplete 进入自动播放完成状态
了解当前屏幕类型

全屏、小窗、非全屏分别是不同的实例,在继承JzvdStd后,通过mCurrentScreen变量,取得当前屏幕类型

  • SCREEN_WINDOW_NORMAL 普通窗口(进入全屏之前的)
  • SCREEN_WINDOW_LIST 列表窗口(进入全屏之前)
  • SCREEN_WINDOW_FULLSCREEN 全屏
  • SCREEN_WINDOW_TINY 小窗 ####事件
  • 复写onProgress函数,取得每次播放器设置底部seekBar的进度回调
  • 调用changeUrl函数,切换url
  • 复写onClick函数,取得各种按钮的点击事件
  • 复写onTouch函数,取得全屏之后的手势操作

一些需求实现(以下实现都是本人的思考逻辑和借鉴一些网络,不完善,要根据你自己项目实际情况来)

1.会员试看功能 首先从思路上理清步骤

  • 首先拿到当前播放时间和是试看时间做判断(考虑拖动进度条超过试看时间)
  • 从后台拿到特定字段判断是否付费
  • 弹出试看结束功能Dialog
  • 付费完回来继续播放(省去付费步骤)———取消

根据自己项目的实际情况来 ,这里只是简单的测试
public class TryToSeeVideo extends JzvdStd {
RelativeLayout mRelativeLayout;
TextView mExit, mPay, mTryToSee;
boolean isNoPay;

public TryToSeeVideo(Context context) {
super(context);
}

public TryToSeeVideo(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void init(Context context) {
super.init(context);
mRelativeLayout = findViewById(R.id.try_to_see_tip);
mExit = findViewById(R.id.exit); //退出按钮
mPay = findViewById(R.id.pay); //支付按钮
mTryToSee = findViewById(R.id.try_see); //重新试看按钮
mExit.setOnClickListener(this);
mPay.setOnClickListener(this);
mTryToSee.setOnClickListener(this);
}

@Override
public int getLayoutId() {
return R.layout.try_to_see_video_layout;
}

@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.exit:
//finish界面 建议回调出当前事件
break;
case R.id.pay:
//进入支付界面 支付成功后 Jzvd.goOnPlayOnResume();
getContext().startActivity(new Intent(getContext(), ActivityMain.class)); //模拟跳转支付界面
break;
case R.id.try_see:
JZMediaManager.seekTo(0);//回到0秒
Jzvd.goOnPlayOnResume();
progressBar.setProgress(0);
mRelativeLayout.setVisibility(GONE);
break;
}
}

/**

  • @param progress 百分比
  • @param position 当前时间
  • @param duration 总时长
    */
    @Override
    public void onProgress(int progress, long position, long duration) {
    super.onProgress(progress, position, duration);
    long totalSeconds = position / 1000;
    if (true) { //这里是从服务器拿到特定字段判断是否付费 这里模拟未付费
    if (totalSeconds >= 30) { //考虑未付费情况下拖动进度条超过试看时间
    if (!isNoPay) { //加个标记 因为此函数一直在回调
    JZMediaManager.seekTo(30000); //回到30秒
    progressBar.setProgress(30);
    mRelativeLayout.setVisibility(VISIBLE); //在适当的时候隐藏
    Jzvd.goOnPlayOnPause(); //在适当的时候(支付成功后)播放
    startButton.setEnabled(false); //在适当的时候取消
    isNoPay = true;
    }
    }
    }
    }

@Override
public void onStatePlaying() {
super.onStatePlaying();
isNoPay = false;
startButton.setEnabled(true);
}
}

2.列表页到详情页无时差播放 3.列表自动播放 4.自动播放下一集剧集

函数 changeUrl 三个重载 根据自己的实际情况来
  • changeUrl(String url, String title, long seekToInAdvance) //seekToInAdvance 时间
  • changeUrl(JZDataSource jzDataSource, long seekToInAdvance)
  • changeUrl(int urlMapIndex, long seekToInAdvance) 这里是演示自动播放下一集(如果要自己选集,自定义UI定义出剧集列表,调用上面三个任意一个)

public class AutoPlayNextVideo extends JzvdStd {
int UrlIndex = 0; //剧集标识
public AutoPlayNextVideo(Context context) {
super(context);
}

public AutoPlayNextVideo(Context context, AttributeSet attrs) {
super(context, attrs);
}

/**

  • 自动播放下一集
  • 若果需要手动选集 自定义Ui定义出剧集列表 调用相关changeUrl
    */
    @Override
    public void onAutoCompletion() {
    super.onAutoCompletion();
    if (UrlIndex<videoUrlList.length){
    UrlIndex++;
    changeUrl(videoUrlList[UrlIndex], “各剧集的标题”, 0);
    }
    }
    }

倍速播放

public class JzvdStdSpeed extends JzvdStd {
TextView tvSpeed;
int currentSpeedIndex = 2;

public JzvdStdSpeed(Context context) {
super(context);
}

public JzvdStdSpeed(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void init(Context context) {
super.init(context);
tvSpeed = findViewById(R.id.tv_speed);
tvSpeed.setOnClickListener(this);
}

@Override
public void setUp(JZDataSource jzDataSource, int screen) {
super.setUp(jzDataSource, screen);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
tvSpeed.setVisibility(View.VISIBLE);
} else {
tvSpeed.setVisibility(View.GONE);
}
if (jzDataSource.objects == null) {
Object[] object = {2};
jzDataSource.objects = object;
currentSpeedIndex = 2;
} else {
currentSpeedIndex = (int) jzDataSource.objects[0];
}
if (currentSpeedIndex == 2) {
tvSpeed.setText(“倍速”);
} else {
tvSpeed.setText(getSpeedFromIndex(currentSpeedIndex) + “X”);
}
}

@Override
public void onClick(View v) {
super.onClick(v);
if (v.getId() == R.id.tv_speed) {//0.5 0.75 1.0 1.25 1.5 1.75 2.0
if (currentSpeedIndex == 6) {
currentSpeedIndex = 0;
} else {
currentSpeedIndex += 1;
}
JZMediaManager.setSpeed(getSpeedFromIndex(currentSpeedIndex));
tvSpeed.setText(getSpeedFromIndex(currentSpeedIndex) + “X”);
jzDataSource.objects[0] = currentSpeedIndex;
}
}

@Override
public int getLayoutId() {
return R.layout.layout_std_speed;
}

private float getSpeedFromIndex(int index) {
float ret = 0f;
if (index == 0) {
ret = 0.5f;
} else if (index == 1) {
ret = 0.75f;
} else if (index == 2) {
ret = 1.0f;
} else if (index == 3) {
ret = 1.25f;
} else if (index == 4) {
ret = 1.5f;
} else if (index == 5) {
ret = 1.75f;
} else if (index == 6) {
ret = 2.0f;
}
return ret;
}

##常见问题 视频有声音,无画面

  • 开启硬件加速

获取视频某一帧

/**
*  context 上下文
*  uri 视频地址
*  imageView 设置image
*  frameTimeMicros 获取某一时间帧
*/
public static void loadVideoScreenshot(final Context context, String uri, ImageView imageView, long frameTimeMicros) {
RequestOptions requestOptions = RequestOptions.frameOf(frameTimeMicros);
requestOptions.set(FRAME_OPTION, MediaMetadataRetriever.OPTION_CLOSEST);
requestOptions.transform(new BitmapTransformation() {
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
return toTransform;
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
try {
messageDigest.update((context.getPackageName() + “RotateTransform”).getBytes(“utf-8”));
} catch (Exception e) {
e.printStackTrace();
}
}
});
Glide.with(context).load(uri).apply(requestOptions).into(imageView);
}

视频圆角

ViewOutlineProvider (注:该类是5.0的特性,低于5.0没效果,如果要适配5.0以下这里给出一个思路.9图遮罩)
创建一个类继承ViewOutLineProvider 实现改该方法

public class JzViewOutlineProvider extends ViewOutlineProvider {
private float mRadius;
public JzViewOutlineProvider(float radius) {
this.mRadius = radius;
}
@Override
public void getOutline(View view, Outline outline) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
Rect selfRect = new Rect(0, 0,
view.getWeight(),view.getHeight());
outline.setRoundRect(selfRect,mRadius);
}
}
mJzvdStd.setOutlineProvider(new JzViewOutlineProvider(radius));
mJzvdStd.setClipToOutline(true);

点击全屏按钮闪退,报错空指针

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
s ViewOutlineProvider {
private float mRadius;
public JzViewOutlineProvider(float radius) {
this.mRadius = radius;
}
@Override
public void getOutline(View view, Outline outline) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
Rect selfRect = new Rect(0, 0,
view.getWeight(),view.getHeight());
outline.setRoundRect(selfRect,mRadius);
}
}
mJzvdStd.setOutlineProvider(new JzViewOutlineProvider(radius));
mJzvdStd.setClipToOutline(true);

点击全屏按钮闪退,报错空指针

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-Ttj8Haka-1719090770745)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值