关于MediaController的自定义

2024-03-18 09:48
文章标签 自定义 mediacontroller

本文主要是介绍关于MediaController的自定义,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇博客介绍了videoview和自定义该类,这篇想介绍一下MediaController,本人接触android也就几个月,其中还有一些问题,希望和大家一起进步。

自定义其实就是将android的MediaController源码摘出来,然后对其进行改编定义成自己的类。

摘出来和修改如下:

import java.util.Formatter;
import java.util.Locale;import com.android.internal.policy.PolicyManager;import android.content.Context;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
//import android.view.View.OnLayoutChangeListener;
//import android.view.View.OnTouchListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
//import android.widget.FrameLayout.LayoutParams;
//import android.widget.MediaController.MediaPlayerControl;
import android.widget.SeekBar.OnSeekBarChangeListener;public class MediaController extends FrameLayout {private MediaPlayerControl  mPlayer;private Context             mContext;private View                mAnchor;private View                mRoot;private WindowManager       mWindowManager;private Window              mWindow;private View                mDecor;private WindowManager.LayoutParams mDecorLayoutParams;private ProgressBar         mProgress;private TextView            mEndTime, mCurrentTime;private boolean             mShowing;private boolean             mDragging;private static final int    sDefaultTimeout = 3000;private static final int    FADE_OUT = 1;private static final int    SHOW_PROGRESS = 2;private boolean             mUseFastForward;private boolean             mFromXml;private boolean             mListenersSet;private View.OnClickListener mNextListener, mPrevListener;StringBuilder               mFormatBuilder;Formatter                   mFormatter;private ImageButton         mPauseButton;private ImageButton         mFfwdButton;private ImageButton         mRewButton;private ImageButton         mNextButton;private ImageButton         mPrevButton;public MediaController(Context context, AttributeSet attrs) {super(context, attrs);mRoot = this;mContext = context;mUseFastForward = true;mFromXml = true;}@Overridepublic void onFinishInflate() {if (mRoot != null)initControllerView(mRoot);}public MediaController(Context context, boolean useFastForward) {super(context);mContext = context;mUseFastForward = useFastForward;initFloatingWindowLayout();initFloatingWindow();}public MediaController(Context context) {this(context, true);}private void initFloatingWindow() {mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);mWindow = PolicyManager.makeNewWindow(mContext);mWindow.setWindowManager(mWindowManager, null, null);mWindow.requestFeature(Window.FEATURE_NO_TITLE);mDecor = mWindow.getDecorView();mDecor.setOnTouchListener(mTouchListener);mWindow.setContentView(this);mWindow.setBackgroundDrawableResource(android.R.color.transparent);mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);setFocusable(true);setFocusableInTouchMode(true);setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);requestFocus();}private void initFloatingWindowLayout() {mDecorLayoutParams = new WindowManager.LayoutParams();WindowManager.LayoutParams p = mDecorLayoutParams;p.gravity = Gravity.TOP;p.height = LayoutParams.WRAP_CONTENT;p.x = 0;p.format = PixelFormat.TRANSLUCENT;p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;p.token = null;p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;}private void updateFloatingWindowLayout() {int [] anchorPos = new int[2];mAnchor.getLocationOnScreen(anchorPos);WindowManager.LayoutParams p = mDecorLayoutParams;p.width = mAnchor.getWidth();p.y = anchorPos[1] + mAnchor.getHeight();}// This is called whenever mAnchor's layout bound changesprivate OnLayoutChangeListener mLayoutChangeListener =new OnLayoutChangeListener() {public void onLayoutChange(View v, int left, int top, int right,int bottom, int oldLeft, int oldTop, int oldRight,int oldBottom) {updateFloatingWindowLayout();if (mShowing) {mWindowManager.updateViewLayout(mDecor, mDecorLayoutParams);}}};private OnTouchListener mTouchListener = new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {if (mShowing) {hide();}}return false;}};public void setMediaPlayer(MediaPlayerControl player) {mPlayer = player;updatePausePlay();}/*** Set the view that acts as the anchor for the control view.* This can for example be a VideoView, or your Activity's main view.* @param view The view to which to anchor the controller when it is visible.*/public void setAnchorView(View view) {if (mAnchor != null) {mAnchor.removeOnLayoutChangeListener(mLayoutChangeListener);}mAnchor = view;if (mAnchor != null) {mAnchor.addOnLayoutChangeListener(mLayoutChangeListener);}FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);removeAllViews();View v = makeControllerView();addView(v, frameParams);}/*** Create the view that holds the widgets that control playback.* Derived classes can override this to create their own.* @return The controller view.* @hide This doesn't work as advertised*/protected View makeControllerView() {LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);mRoot = inflate.inflate(R.layout.media_controller, null);initControllerView(mRoot);return mRoot;}private void initControllerView(View v) {mPauseButton = (ImageButton) v.findViewById(R.id.pause);if (mPauseButton != null) {mPauseButton.requestFocus();mPauseButton.setOnClickListener(mPauseListener);}mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);if (mFfwdButton != null) {Log.v("MediaController", "into the mFfwdButton.setOnClickListener");mFfwdButton.setOnClickListener(mFfwdListener);if (!mFromXml) {mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);}}mRewButton = (ImageButton) v.findViewById(R.id.rew);if (mRewButton != null) {Log.v("MediaController", "into the mRewButton.setOnClickListener");mRewButton.setOnClickListener(mRewListener);if (!mFromXml) {mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);}}// By default these are hidden. They will be enabled when setPrevNextListeners() is called mNextButton = (ImageButton) v.findViewById(R.id.next);if (mNextButton != null && !mFromXml && !mListenersSet) {mNextButton.setVisibility(View.GONE);}mPrevButton = (ImageButton) v.findViewById(R.id.prev);if (mPrevButton != null && !mFromXml && !mListenersSet) {mPrevButton.setVisibility(View.GONE);}mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_progress);if (mProgress != null) {if (mProgress instanceof SeekBar) {SeekBar seeker = (SeekBar) mProgress;seeker.setOnSeekBarChangeListener(mSeekListener);}mProgress.setMax(1000);}mEndTime = (TextView) v.findViewById(R.id.time);mCurrentTime = (TextView) v.findViewById(R.id.time_current);mFormatBuilder = new StringBuilder();mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());installPrevNextListeners();}/*** Show the controller on screen. It will go away* automatically after 3 seconds of inactivity.*/public void show() {show(sDefaultTimeout);}/*** Disable pause or seek buttons if the stream cannot be paused or seeked.* This requires the control interface to be a MediaPlayerControlExt*/private void disableUnsupportedButtons() {try {if (mPauseButton != null && !mPlayer.canPause()) {mPauseButton.setEnabled(false);}if (mRewButton != null && !mPlayer.canSeekBackward()) {mRewButton.setEnabled(false);}if (mFfwdButton != null && !mPlayer.canSeekForward()) {mFfwdButton.setEnabled(false);}} catch (IncompatibleClassChangeError ex) {}}/*** Show the controller on screen. It will go away* automatically after 'timeout' milliseconds of inactivity.* @param timeout The timeout in milliseconds. Use 0 to show* the controller until hide() is called.*/public void show(int timeout) {if (!mShowing && mAnchor != null) {setProgress();if (mPauseButton != null) {mPauseButton.requestFocus();}disableUnsupportedButtons();updateFloatingWindowLayout();mWindowManager.addView(mDecor, mDecorLayoutParams);mShowing = true;}updatePausePlay();mHandler.sendEmptyMessage(SHOW_PROGRESS);Message msg = mHandler.obtainMessage(FADE_OUT);if (timeout != 0) {mHandler.removeMessages(FADE_OUT);mHandler.sendMessageDelayed(msg, timeout);}}public boolean isShowing() {return mShowing;}/*** Remove the controller from the screen.*/public void hide() {if (mAnchor == null)return;if (mShowing) {try {mHandler.removeMessages(SHOW_PROGRESS);mWindowManager.removeView(mDecor);} catch (IllegalArgumentException ex) {Log.w("MediaController", "already removed");}mShowing = false;}}private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {int pos;switch (msg.what) {case FADE_OUT:hide();break;case SHOW_PROGRESS:pos = setProgress();if (!mDragging && mShowing && mPlayer.isPlaying()) {msg = obtainMessage(SHOW_PROGRESS);sendMessageDelayed(msg, 1000 - (pos % 1000));}break;}}};private String stringForTime(int timeMs) {int totalSeconds = timeMs / 1000;int seconds = totalSeconds % 60;int minutes = (totalSeconds / 60) % 60;int hours   = totalSeconds / 3600;mFormatBuilder.setLength(0);if (hours > 0) {return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();} else {return mFormatter.format("%02d:%02d", minutes, seconds).toString();}}private int setProgress() {if (mPlayer == null || mDragging) {return 0;}int position = mPlayer.getCurrentPosition();int duration = mPlayer.getDuration();if (mProgress != null) {if (duration > 0) {// use long to avoid overflowlong pos = 1000L * position / duration;mProgress.setProgress( (int) pos);}int percent = mPlayer.getBufferPercentage();mProgress.setSecondaryProgress(percent * 10);}if (mEndTime != null)mEndTime.setText(stringForTime(duration));if (mCurrentTime != null)mCurrentTime.setText(stringForTime(position));return position;}@Overridepublic boolean onTouchEvent(MotionEvent event) {show(sDefaultTimeout);return true;}@Overridepublic boolean onTrackballEvent(MotionEvent ev) {show(sDefaultTimeout);return false;}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();final boolean uniqueDown = event.getRepeatCount() == 0&& event.getAction() == KeyEvent.ACTION_DOWN;if (keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE|| keyCode == KeyEvent.KEYCODE_SPACE) {if (uniqueDown) {doPauseResume();show(sDefaultTimeout);if (mPauseButton != null) {mPauseButton.requestFocus();}}return true;} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {if (uniqueDown && !mPlayer.isPlaying()) {mPlayer.start();updatePausePlay();show(sDefaultTimeout);}return true;} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {if (uniqueDown && mPlayer.isPlaying()) {mPlayer.pause();updatePausePlay();show(sDefaultTimeout);}return true;} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN|| keyCode == KeyEvent.KEYCODE_VOLUME_UP|| keyCode == KeyEvent.KEYCODE_VOLUME_MUTE|| keyCode == KeyEvent.KEYCODE_CAMERA) {// don't show the controls for volume adjustmentreturn super.dispatchKeyEvent(event);} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {if (uniqueDown) {hide();}return true;}show(sDefaultTimeout);return super.dispatchKeyEvent(event);}private View.OnClickListener mPauseListener = new View.OnClickListener() {public void onClick(View v) {Log.v("MediaController", "into the mPauseListener");doPauseResume();show(sDefaultTimeout);}};private void updatePausePlay() {if (mRoot == null || mPauseButton == null)return;if (mPlayer.isPlaying()) {mPauseButton.setImageResource(R.drawable.media_pause);} else {mPauseButton.setImageResource(R.drawable.media_play);}}private void doPauseResume() {if (mPlayer.isPlaying()) {mPlayer.pause();} else {mPlayer.start();}updatePausePlay();}private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {public void onStartTrackingTouch(SeekBar bar) {show(3600000);mDragging = true;mHandler.removeMessages(SHOW_PROGRESS);}public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {if (!fromuser) {// We're not interested in programmatically generated changes to// the progress bar's position.return;}long duration = mPlayer.getDuration();long newposition = (duration * progress) / 1000L;mPlayer.seekTo( (int) newposition);if (mCurrentTime != null)mCurrentTime.setText(stringForTime( (int) newposition));}public void onStopTrackingTouch(SeekBar bar) {mDragging = false;setProgress();updatePausePlay();show(sDefaultTimeout);mHandler.sendEmptyMessage(SHOW_PROGRESS);}};@Overridepublic void setEnabled(boolean enabled) {if (mPauseButton != null) {mPauseButton.setEnabled(enabled);}if (mFfwdButton != null) {mFfwdButton.setEnabled(enabled);}if (mRewButton != null) {mRewButton.setEnabled(enabled);}if (mNextButton != null) {mNextButton.setEnabled(enabled && mNextListener != null);}if (mPrevButton != null) {mPrevButton.setEnabled(enabled && mPrevListener != null);}if (mProgress != null) {mProgress.setEnabled(enabled);}disableUnsupportedButtons();super.setEnabled(enabled);}@Overridepublic void onInitializeAccessibilityEvent(AccessibilityEvent event) {super.onInitializeAccessibilityEvent(event);event.setClassName(MediaController.class.getName());}@Overridepublic void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {super.onInitializeAccessibilityNodeInfo(info);info.setClassName(MediaController.class.getName());}private View.OnClickListener mRewListener = new View.OnClickListener() {public void onClick(View v) {Log.v("MediaController", "into the mRew button");int pos = mPlayer.getCurrentPosition();pos -= 5000; // millisecondsmPlayer.seekTo(pos);setProgress();show(sDefaultTimeout);}};private View.OnClickListener mFfwdListener = new View.OnClickListener() {public void onClick(View v) {Log.v("MediaController", "into the mFfw button");int pos = mPlayer.getCurrentPosition();pos += 15000; // millisecondsmPlayer.seekTo(pos);setProgress();show(sDefaultTimeout);}};private void installPrevNextListeners() {if (mNextButton != null) {mNextButton.setOnClickListener(mNextListener);mNextButton.setEnabled(mNextListener != null);}if (mPrevButton != null) {mPrevButton.setOnClickListener(mPrevListener);mPrevButton.setEnabled(mPrevListener != null);}}public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {mNextListener = next;mPrevListener = prev;mListenersSet = true;if (mRoot != null) {installPrevNextListeners();if (mNextButton != null && !mFromXml) {mNextButton.setVisibility(View.VISIBLE);}if (mPrevButton != null && !mFromXml) {mPrevButton.setVisibility(View.VISIBLE);}}}public interface MediaPlayerControl {void    start();void    pause();int     getDuration();int     getCurrentPosition();void    seekTo(int pos);boolean isPlaying();int     getBufferPercentage();boolean canPause();boolean canSeekBackward();boolean canSeekForward();}
}
直接应用源代码会提示很多错误,比如资源找不到等,其中有一个layout.media_controller文件,布局如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#CC000000"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:paddingTop="4dip"android:orientation="horizontal"><ImageButton android:id="@+id/prev" style="@style/MediaButton.Previous" /><ImageButton android:id="@+id/rew" style="@style/MediaButton.Rew" /><ImageButton android:id="@+id/pause" style="@style/MediaButton.Play" /><ImageButton android:id="@+id/ffwd" style="@style/MediaButton.Ffwd" /><ImageButton android:id="@+id/next" style="@style/MediaButton.Next" /> </LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextView android:id="@+id/time_current"android:textSize="14sp"android:textStyle="bold"android:paddingTop="4dip"android:paddingStart="4dip"android:layout_gravity="center_horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingEnd="4dip"android:textColor="@color/dim_foreground_dark" /><SeekBarandroid:id="@+id/mediacontroller_progress"style="?android:attr/progressBarStyleHorizontal"android:layout_width="0dip"android:layout_weight="1"android:layout_height="32dip"android:layout_alignParentStart="true"android:layout_alignParentEnd="true" /><TextView android:id="@+id/time"android:textSize="14sp"android:textStyle="bold"android:paddingTop="4dip"android:paddingEnd="4dip"android:layout_gravity="center_horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingStart="4dip"android:textColor="@color/dim_foreground_dark" /></LinearLayout></LinearLayout>

其中有一些style风格如下:

<style name="MediaButton"><item name="android:background">@null</item><item name="android:layout_width">71dip</item><item name="android:layout_height">52dip</item></style><style name="MediaButton.Previous"><item name="android:src">@android:drawable/ic_media_previous</item></style><style name="MediaButton.Next"><item name="android:src">@android:drawable/ic_media_next</item></style><style name="MediaButton.Play"><item name="android:src">@android:drawable/ic_media_play</item></style><style name="MediaButton.Ffwd"><item name="android:src">@android:drawable/ic_media_ff</item></style><style name="MediaButton.Rew"><item name="android:src">@android:drawable/ic_media_rew</item></style><style name="MediaButton.Pause"><item name="android:src">@android:drawable/ic_media_pause</item></style>
可以根据其中的UI更换成自己的风格。

最棘手的是下面几段代码:

mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);mWindow = PolicyManager.makeNewWindow(mContext);mWindow.setWindowManager(mWindowManager, null, null);mWindow.requestFeature(Window.FEATURE_NO_TITLE);mDecor = mWindow.getDecorView();mDecor.setOnTouchListener(mTouchListener);mWindow.setContentView(this);mWindow.setBackgroundDrawableResource(android.R.color.transparent);
PolicyManager.makeNewWindow是一个内部类,用于新建一个window窗口,该类的包为:

import com.android.internal.policy.PolicyManager;

这个包为android的core层使用的,应用程序无法调用。由于对这些函数不胜了解,到现在我任然没有搞懂这段代码用什么替换,如果有哪位大神知道,可以告知我,本人不胜感激。

我这地方用了另一种方法搞定编译,PolicyManager.makeNewWindow这个函数android内部是有的,位于system/framwork/framwork.odex中,但是在eclipse中的android的jar包中找不到这个类,所以一种方法是将这个类的jar包直接加入到工程当中,经过网络搜索,捣鼓一通以后重新得到了一个包含com.android.internal的jar包。


下载地址:

http://download.csdn.net/detail/taoxugang2012/6509377

由于时间倡促,技术不够强硬,这个东西暂时就这么做,严格上来说,应该用应用层的接口方法来替换该部分代码。


到此,有了自定义的videoview和自定义MediaController,那么一个播放器也就差不多了,比起自己重零做起,android的这两个类自然有它的好处,使用的人可以根据这个类修改其中的UI界面,对其它部分进行优化。

现在就这么做吧,等我技术知识储备好了,再重新写一个更完美的。

这篇关于关于MediaController的自定义的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/821957

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

鸿蒙开发中实现自定义弹窗 (CustomDialog)

效果图 #思路 创建带有 @CustomDialog 修饰的组件 ,并且在组件内部定义controller: CustomDialogController 实例化CustomDialogController,加载组件,open()-> 打开对话框 , close() -> 关闭对话框 #定义弹窗 (CustomDialog)是什么? CustomDialog是自定义弹窗,可用于广告、中

mybatis框架基础以及自定义插件开发

文章目录 框架概览框架预览MyBatis框架的核心组件MyBatis框架的工作原理MyBatis框架的配置MyBatis框架的最佳实践 自定义插件开发1. 添加依赖2. 创建插件类3. 配置插件4. 启动类中注册插件5. 测试插件 参考文献 框架概览 MyBatis是一个优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射,为开发者提供了极大的灵活性和便利性。以下是关于M

vue2实践:第一个非正规的自定义组件-动态表单对话框

前言 vue一个很重要的概念就是组件,作为一个没有经历过前几代前端开发的我来说,不太能理解它所带来的“进步”,但是,将它与后端c++、java类比,我感觉,组件就像是这些语言中的类和对象的概念,通过封装好的组件(类),可以通过挂载的方式,非常方便的调用其提供的功能,而不必重新写一遍实现逻辑。 我们常用的element UI就是由饿了么所提供的组件库,但是在项目开发中,我们可能还需要额外地定义一