热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自定义View实现炫酷进度条

本篇博客主要介绍利用自定义View来实现自己想要的进度加载效果,其中涉及到的内容不会说的很多,但是我会稍微解释一下,其实只要有了思路都好处理。而且个人感觉自己写一个自定义View要比看别人写的自定

本篇博客主要介绍利用自定义View来实现自己想要的进度加载效果,其中涉及到的内容不会说的很多,但是我会稍微解释一下,其实只要有了思路都好处理。而且个人感觉自己写一个自定义View要比看别人写的自定义View要简单一点,因为你很明白里面属性的意义,看别人的自定义View还需要不断的判断每个属性的作用,然后是各种计算什么的,感觉不是很好!!(这个炫酷的进度条不是我的想法,是我在网上看到的,不过很不好意思,我当时只是从他的git仓库中把代码clone下来,没有保存原文链接,如果作者看到了,可以告诉我一下,我会将原文链接重新添加上去)。不过这篇的自定义View的实现,是我自己写的,没有完全拷贝作者的代码!!!详细情况可以看一下我的代码!!

好了,废话不多说了,先看一下效果图:
这里写图片描述这里写图片描述这里写图片描述

具体的代码的执行效果就是如上图所示,效果不是很好,还有非常大的优化空间,有兴趣的朋友可以自己更改我的代码,或者直接推倒重写,谢谢!!!

主布局文件:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.administrator.customview.MainActivity">


<com.example.administrator.customview.CustomView
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content">


com.example.administrator.customview.CustomView>
<Button
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startProgressAnimation"
android:layout_below="@id/pb"
android:text="@string/start_animation"/>

RelativeLayout>

在这里主要是将我自定义的View引入到布局中,就不做过多的介绍了!!!

Activity文件:

package com.example.administrator.customview;

import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

private CustomView cv;
private int progressValue = 0;
private boolean mProgressIsRunning = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cv = (CustomView) findViewById(R.id.pb);
}

public void startProgressAnimation(View view){
if (mProgressIsRunning){
timer.cancel();
timer.onFinish();
}else{
mProgressIsRunning = true;
if (progressValue>=100){
progressValue = 0;
}
timer.start();
}
}

private CountDownTimer timer = new CountDownTimer(Integer.MAX_VALUE,100) {
@Override
public void onTick(long millisUntilFinished) {
cv.setProgressValue(progressValue);
progressValue ++;
}

@Override
public void onFinish() {
mProgressIsRunning = false;
}
};
}

使用一个定时器来模拟加载时value变化,根据时间不断的调整Value值,给人进度不断变化的感觉。这里的cv就是我们自定义的View。

CustomView文件(这个很关键,主要就是这个文件):

package com.example.administrator.customview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
* Created by zhuyuqiang on 2017/3/13.
*/


public class CustomView extends View {

private final int WHITE_COLOR = Color.WHITE;
private final int ORANGE_COLOR = 0xffffa800;
//确定叶子旋转方向
private final int ROTATE_RIGHT = 0;
private final int ROTATE_LEFT = 1;
private final int ROTATE_DEGREE = 5;
//确定叶子垂直方向的振幅大小
private final int SMALL_AMPLITUDE = 0;
private final int MIDDLE_AMPLITUDE = 1;
private final int BIG_AMPLITUDE = 2;
private final int SMALL_Y = 1;
private final int MIDDLE_Y = 2;
private final int BIG_Y = 3;
//确定叶子水平方向的移动大小
private final int SMALL_TRANSITION = 0;
private final int MIDDLE_TRANSITION = 1;
private final int BIG_TRANSITION = 2;
private final int SMALL_X = 5;
private final int MIDDLE_X = 10;
private final int BIG_X = 15;
private Paint mWhitePaint,mOrangePaint,mBitmapPaint;
private int mPadding_left,mPadding_top,mPadding_right,mPadding_bottom;
private Point mLeftCircleCenter,mRightCircleCenter,mFengshanPoint;
private BitmapContainer mLeafContainer,mFengShanContainer,mBg_Container;
private Matrix mFengShanRotate,mLeafMatrix,mTextMatrix;
private int startDegree = 0;
private int mProgressValue = 0;
private int radius;
private final float MAX_PROGRESS_VALUE = 100;
private RectF mLeftArcRect;
private Rect mTextRect;
private final int max = 10;
private int y_step = 2;
private final String mFinish= "100%";
private float mTextScale = 0.1f;
private int mTextSize = 42;
private List mLeaves = new ArrayList<>();
private onProgressChangedListener listener;
public interface onProgressChangedListener{
void onProgressValueChanged(int progressValue);
}

public CustomView(Context context) {
this(context,null);
}

public CustomView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}

public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr,0);
}

public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initAttrs();
initBitmaps();
initPaints();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getCustomMeasureWidth(widthMeasureSpec),getCustomMeasureHeight(heightMeasureSpec));
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
initKeyPoints();
initMatrix();
generateLeaves();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLeafs(canvas);
drawProgress(canvas);
canvas.drawBitmap(mBg_Container.src,mPadding_left,mPadding_top,mBitmapPaint);
drawFengShan(canvas);
postInvalidateDelayed(50);
}

private void drawLeafs(Canvas canvas) {
int mProgressWidth = (int) ((mProgressValue/MAX_PROGRESS_VALUE)*(getWidth()-mPadding_left-mPadding_right-radius));
for (Leaf mLeaf:mLeaves){
canvas.save();
mLeafMatrix.reset();
mLeafMatrix.preRotate(mLeaf.degree,mLeafContainer.width/2,mLeafContainer.height/2);
switch (mLeaf.rotateDirection){
case ROTATE_LEFT:
mLeaf.degree = mLeaf.degree-ROTATE_DEGREE;
break;
case ROTATE_RIGHT:
mLeaf.degree = mLeaf.degree+ROTATE_DEGREE;
break;
}
mLeafMatrix.postTranslate(mLeaf.position.x-50,mLeaf.position.y-mLeafContainer.height/2);
switch (mLeaf.transition){
case SMALL_TRANSITION:
mLeaf.position.x = mLeaf.position.x - SMALL_X;
break;
case MIDDLE_TRANSITION:
mLeaf.position.x = mLeaf.position.x - MIDDLE_X;
break;
case BIG_TRANSITION:
mLeaf.position.x = mLeaf.position.x - BIG_X;
break;
}
switch (mLeaf.transition){
case SMALL_AMPLITUDE:
if(mLeaf.position.y<(mRightCircleCenter.y-max)){
y_step = -SMALL_Y;
}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){
y_step = SMALL_Y;
}
break;
case MIDDLE_AMPLITUDE:
if(mLeaf.position.y<(mRightCircleCenter.y-max)){
y_step = -MIDDLE_Y;
}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){
y_step = MIDDLE_Y;
}
break;
case BIG_AMPLITUDE:
if(mLeaf.position.y<(mRightCircleCenter.y-max)){
y_step = -BIG_Y;
}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){
y_step = BIG_Y;
}
break;
}

mLeaf.position.y = mLeaf.position.y - y_step;
if(mLeaf.position.x > mProgressWidth+mPadding_left+10){
canvas.drawBitmap(mLeafContainer.src,mLeafMatrix,mBitmapPaint);
}else{
mLeaf.position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y-mLeafContainer.height/2);
mLeaf.transition = new Random().nextInt(3);
mLeaf.degree = new Random().nextInt(360);
mLeaf.rotateDirection = new Random().nextInt(2);
mLeaf.amplitude = new Random().nextInt(3);
}
canvas.restore();
}
}

public void setProgressValue(int value){
this.mProgressValue = value;
invalidate();
}

public int getProgressValue(){
return mProgressValue;
}

public void setProgressChangeListener(onProgressChangedListener listener){
this.listener = listener;
}

private void drawProgress(Canvas canvas) {

int shouldDrawWidth = (int) ((mProgressValue/MAX_PROGRESS_VALUE)*(getWidth()-mPadding_left-mPadding_right-radius));
Log.d("zyq_progress","shouldDrawWidth = "+shouldDrawWidth);
if(shouldDrawWidth<(mLeftCircleCenter.x-mPadding_left)){
float degree = (float) Math.toDegrees(Math.acos((radius - shouldDrawWidth)
/ (float) radius));
canvas.save();
canvas.drawArc(mLeftArcRect,180-degree,2*degree,false,mOrangePaint);
}else{
if (shouldDrawWidth>mRightCircleCenter.x){
shouldDrawWidth = mRightCircleCenter.x;
}
canvas.save();
canvas.drawArc(mLeftArcRect,90,180,true,mOrangePaint);
canvas.drawRect(radius+mPadding_left,mPadding_top,shouldDrawWidth,2*radius+mPadding_top,mOrangePaint);
canvas.restore();
}
if(listener != null){
listener.onProgressValueChanged(mProgressValue);
}
}

private void drawFengShan(Canvas canvas){
if(mProgressValue<100){
startDegree = startDegree+15;
canvas.save();
mFengShanRotate.reset();
mFengShanRotate.preRotate(startDegree,mFengShanContainer.width/2,mFengShanContainer.height/2);
mFengShanRotate.postTranslate(mFengshanPoint.x,mFengshanPoint.y);
Log.i("zyq","mFengshanPoint.x ="+mFengshanPoint.x+" mFengshanPoint.y="+mFengshanPoint.y);
canvas.drawBitmap(mFengShanContainer.src,mFengShanRotate,mBitmapPaint);
canvas.restore();
}else{
canvas.save();
mTextMatrix.reset();
if(mTextScale<1){
mWhitePaint.setTextSize(mTextSize*mTextScale);
mWhitePaint.getTextBounds(mFinish,0,mFinish.length(),mTextRect);
}else{
mWhitePaint.setTextSize(mTextSize);
mWhitePaint.getTextBounds(mFinish,0,mFinish.length(),mTextRect);
}
canvas.drawText(mFinish,0,mFinish.length(),mRightCircleCenter.x-((mTextRect.width())/2),
mRightCircleCenter.y+(mTextRect.height()/2),mWhitePaint);
mTextScale = mTextScale+0.1f;
canvas.restore();
}

}

private void initKeyPoints(){
mLeftCircleCenter = new Point();
radius = getHeight()/2-mPadding_bottom/2-mPadding_top/2;
mLeftCircleCenter.y = radius+mPadding_top;
mLeftCircleCenter.x = radius+mPadding_right;
Log.d("zyq_point","View,hljs-string">" mLeftCircleCenter.x = "+mLeftCircleCenter.x+"mLeftCircleCenter.y="+mLeftCircleCenter.y);
mRightCircleCenter = new Point();
mRightCircleCenter.y = radius+mPadding_top;
mRightCircleCenter.x = getWidth()-radius-mPadding_right;
Log.d("zyq_point","mRightCircleCenter.x = "+mRightCircleCenter.x+"mRightCircleCenter.y="+mRightCircleCenter.y);
mFengshanPoint = new Point();
mFengshanPoint.x = mRightCircleCenter.x-mFengShanContainer.width/2;
mFengshanPoint.y = mRightCircleCenter.y-mFengShanContainer.height/2;
Log.d("zyq_point","mFengshanPoint.x = "+mFengshanPoint.x+"mFengshanPoint.y="+mFengshanPoint.y);
}

private void initPaints(){
mWhitePaint = new Paint();
mWhitePaint.setAntiAlias(true);
mWhitePaint.setDither(true);
mWhitePaint.setTextSize(32);
mWhitePaint.setTextAlign(Paint.Align.LEFT);
mWhitePaint.setStrokeWidth(6f);
mWhitePaint.setColor(WHITE_COLOR);


mOrangePaint = new Paint();
mOrangePaint.setAntiAlias(true);
mOrangePaint.setDither(true);
mOrangePaint.setColor(ORANGE_COLOR);
mOrangePaint.setStyle(Paint.Style.FILL);

mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setDither(true);
mBitmapPaint.setFilterBitmap(true);
}

private void initBitmaps(){
Bitmap mLeaf = ((BitmapDrawable)getResources().getDrawable(R.drawable.leaf_drawable,null)).getBitmap();
Bitmap mFengShan = ((BitmapDrawable)getResources().getDrawable(R.drawable.fengshan_drawable,null)).getBitmap();
Bitmap mbg_kuang = ((BitmapDrawable)getResources().getDrawable(R.drawable.leaf_kuang_drawable,null)).getBitmap();
mLeafCOntainer= new BitmapContainer();
mLeafContainer.src = mLeaf;
mLeafContainer.width = mLeaf.getWidth();
mLeafContainer.height = mLeaf.getHeight();

mFengShanCOntainer= new BitmapContainer();
mFengShanContainer.src = mFengShan;
mFengShanContainer.width = mFengShan.getWidth();
mFengShanContainer.height = mFengShan.getHeight();
Log.i("zyq","fen:hljs-string">" hljs-keyword">new BitmapContainer();
mBg_Container.src = mbg_kuang;
mBg_Container.width = mbg_kuang.getWidth();
mBg_Container.height = mbg_kuang.getHeight();
Log.i("zyq_Bg_Container","mBg_Container:hljs-string">" hljs-keyword">private void initMatrix(){
mFengShanRotate = new Matrix();
mLeafMatrix = new Matrix();
mTextMatrix = new Matrix();
calculatePosition();
}

private void calculatePosition(){
mLeftArcRect = new RectF();
mLeftArcRect.left = mPadding_left;
mLeftArcRect.top = mPadding_top;
mLeftArcRect.right = 2*radius+mPadding_left;
mLeftArcRect.bottom = 2*radius+mPadding_top;
mTextRect = new Rect();
mWhitePaint.getTextBounds(mFinish,0,mFinish.length(), mTextRect);
}

private class BitmapContainer{
Bitmap src;
int width;
int height;
}

private class Leaf{
Point position;
int degree;
long startTime;
int rotateDirection;
int amplitude;
int transition;
public Leaf(){
position = new Point();
position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y);
degree = new Random().nextInt(360);
startTime = System.currentTimeMillis();
rotateDirection = new Random().nextInt(2);
amplitude = new Random().nextInt(3);
transition = new Random().nextInt(3);
}
public Leaf(int transition){
position = new Point();
position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y);
degree = new Random().nextInt(360);
startTime = System.currentTimeMillis();
rotateDirection = new Random().nextInt(2);
amplitude = new Random().nextInt(3);
this.transition = transition;
}
}

private void generateLeaves() {
if(mLeaves.isEmpty()){
for(int i = 0;i<3;i++){
Leaf l = new Leaf(i);
mLeaves.add(l);
}
}
}

private int getCustomMeasureWidth(int widthMeasureSpec){
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY){
Log.i("zyq_view","view.size = "+size);
return size;
}else{
Log.i("zyq_view","view.width = "+(mBg_Container.width+getPaddingLeft()+getPaddingRight()));
return mBg_Container.width+getPaddingLeft()+getPaddingRight();
}
}

private int getCustomMeasureHeight(int heightMeasureSpec){
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY){
return size;
}else{
return mBg_Container.height+getPaddingTop()+getPaddingBottom();
}
}

private void initAttrs() {
mPadding_left = getPaddingLeft();
mPadding_top = getPaddingTop();
mPadding_right = getPaddingRight();
mPadding_bottom = getPaddingBottom();
Log.i("zyq_pad","left="+mPadding_left+" top="+mPadding_top+" right="+mPadding_right+" bottom="+mPadding_bottom);
}
}

在文件刚开始的时候,定义了各种宽高,比如叶子每次水平移动的距离、垂直移动的距离,旋转的角度、旋转的方向等。基本上来说就是你想控制什么样的动作,就需要你定义什么样的属性,通过属性控制对象的动作。这里的三个图片都是提前准备好的。然后在view中获取这个单个图片对应的bitmap,并获取每个bitmap的宽高,这里的宽高用于以后确定这些bitmap的绘制位置。

在实际的绘制过程中,还需要考虑图层的关系,因为需要有叶子融入的感觉,所以在这里把绘制叶子的步骤放在最前面,这样实现的了叶子融入的感觉。

其次,自定义View中的动画都是通过控制矩阵来实现,比如旋转、移动等。但是字体放大的动画,我试过矩阵,但是不起作用,最后不得已通过改变字体尺寸来实现,希望有知道的朋友可以告诉我一下,不胜感激!!!

其实,其他的动画还好,就是叶子的动画不太好弄,因为需要一种,叶子随机出现的效果,我这里做的不好,希望大神们可以帮忙更改一下!!原作者的叶子动画是与时间关联的,我没有采用,只是限定了叶子出现的位置。具体的情况,还请麻烦各位看代码吧!!!

好了,关于自定义View,暂时就说到这里,以后还将继续介绍有关于自定义View方面的内容,希望大家可以关一下!!!

这是我的微信公众号,如果可以的话,希望您可以帮忙关注一下,这将是对我最大的鼓励了,谢谢!!

公众号

代码地址:
https://github.com/zhuyuqiang2017/CustomView


推荐阅读
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • C# WPF自定义按钮的方法
    本文介绍了在C# WPF中实现自定义按钮的方法,包括使用图片作为按钮背景、自定义鼠标进入效果、自定义按压效果和自定义禁用效果。通过创建CustomButton.cs类和ButtonStyles.xaml资源文件,设计按钮的Style并添加所需的依赖属性,可以实现自定义按钮的效果。示例代码在ButtonStyles.xaml中给出。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
author-avatar
手机用户2502886695
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有