IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android-第一行代码-第三章UI开发(温故而知新)学习记录 -> 正文阅读

[移动开发]android-第一行代码-第三章UI开发(温故而知新)学习记录

第一行代码

继续回顾之前的学习点

第三章 ui设计

ui设计,最关键的一点是通过视觉美感增加用户的粘性,提高一个app的生命周期。

widget常用控件的使用

  1. TextView
    这个文字显示组件已经十分普遍了。详细的内容可以具体参考官方文档。下列的代码实例是copy菜鸟教程中的示例Demo。XML中的语法结构就不赘余了,反正在IDE开发中会进行相应的提示。这其中的属性一般通过翻译也大致比较清晰,若不熟悉可以在文档中进行查看以及在IDE自己敲一敲代码,试一试看看到底是怎么样的效果。
<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"
    android:gravity="center"
    android:background="#8fffad">

    <TextView
        android:id="@+id/txtOne"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:gravity="center"
        android:text="TextView(显示框)"
        android:textColor="#EA5246"
        android:textStyle="bold|italic"
        android:background="#000000"
        android:textSize="18sp" />

</RelativeLayout>

  1. Button
    按钮的设计可以很多彩,button对于ui设计来说是中流砥柱。在活动中的跳转也一般通过button来实现的。不过方法有很多,不局限于一种,但我们更乐于选取最优的一个方法。具体的一些实现方法和相应的花哨的用法在菜鸟教程中可以参考。
<Button
        android:id="@+id/btnOne"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:background="@drawable/btn_bg1"
        android:text="按钮"/>
    
    
    <Button
        android:id="@+id/btnTwo"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:text="按钮不可用"/>

其中强调一个小点,button默认的字符串都是大写的。
如果要关闭这一个功能需要在xml中添加如下代码:
android:textAllCaps="false"关闭大写。
实现button的点击监听方法主要有实现接口方法和使用内部类以及匿名类。方法的实现看个人喜好。

  1. EditView
    文字编辑和输入都需要这个组件widget。
 <EditText
        android:id="@+id/input"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:gravity="start"
        android:background="#ffffff"
        android:layout_marginTop="20dp"
        android:layout_marginHorizontal="12dp"
        android:padding="10dp"
        android:hint="请输入你想说的内容"/>

值得注意的一点是hint是提示语句,可以暗示说明用户需要在这里应该输入那些数据信息。
在ui中因为有时候用户输入的数据很多很长导致ui变形;这是可以参考一下代码配置android:maxLines进行限制。这样就不会使得整个ui变得畸形。

  1. ImageView
    图片,这一个对于所有的用户体验来说是最可观的,也是最直接的widget组件。

在API文档中我们发现ImageView有两个可以设置图片的属性,分别是:src和background

①background通常指的都是背景,而src指的是内容!!
②当使用src填入图片时,是按照图片大小直接填充,并不会进行拉伸
而使用background填入图片,则是会根据ImageView给定的宽度来进行拉伸

 <ImageView  
        android:layout_width="200dp"  
        android:layout_height="wrap_content"  
        android:background="@drawable/pen" />  
  
    <ImageView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:src="@drawable/pen" />  

一般图片资源都会放在drawable下。

  1. ProgressBar

进度条,这里跟用户交互一般是在一些比较耗时的场景下使用。这里会给用户一种比较良好的交互感。

 <ProgressBar
        style="@android:style/Widget.ProgressBar.Large"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

这一部分的操作在xml中比较少,更多的是结合实际的业务代码逻辑在逻辑中进行设计和操作。

  1. AlertDialog

    对话框这一部分主要是避免用户的一些误删操作等等。增强这个app的可控性。这一部分主要还是在逻辑代码中实现。当然你也可以自己设计属于自己风格的一些样式,最后在组装起来。

//普通对话框
case R.id.btn_dialog_one:
                alert = null;
                builder = new AlertDialog.Builder(mContext);
                alert = builder.setIcon(R.mipmap.ic_icon_fish)
                        .setTitle("系统提示:")
                        .setMessage("这是一个最普通的AlertDialog,\n带有三个按钮,分别是取消,中立和确定")
                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(mContext, "你点击了取消按钮~", Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(mContext, "你点击了确定按钮~", Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setNeutralButton("中立", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(mContext, "你点击了中立按钮~", Toast.LENGTH_SHORT).show();
                            }
                        }).create();             //创建AlertDialog对象
                alert.show();                    //显示对话框
                break;

这个alertDialog主要就是一个builder重要点。不要忘记show出来!!!跟Toast一样,要是不show出来写了也没有,用户看不到。

  1. ProgressDialog

进度条对话框,这个和AlertDialog其实功能上差不多,只是多了一个progressBar进行动态的交互设计。这一点也是一般用在高耗时的工作上。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_one;
    private Button btn_two;
    private Button btn_three;
    private ProgressDialog pd1 = null;
    private ProgressDialog pd2 = null;
    private final static int MAXVALUE = 100;
    private int progressStart = 0;
    private int add = 0;
    private Context mContext = null;


    //定义一个用于更新进度的Handler,因为只能由主线程更新界面,所以要用Handler传递信息
    final Handler hand = new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            //这里的话如果接受到信息码是123
            if(msg.what == 123)
            {
                //设置进度条的当前值
                pd2.setProgress(progressStart);
            }
            //如果当前大于或等于进度条的最大值,调用dismiss()方法关闭对话框
            if(progressStart >= MAXVALUE)
            {
                pd2.dismiss();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        bindViews();
    }

    private void bindViews() {
        btn_one = (Button) findViewById(R.id.btn_one);
        btn_two = (Button) findViewById(R.id.btn_two);
        btn_three = (Button) findViewById(R.id.btn_three);
        btn_one.setOnClickListener(this);
        btn_two.setOnClickListener(this);
        btn_three.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_one:
                //这里的话参数依次为,上下文,标题,内容,是否显示进度,是否可以用取消按钮关闭
                ProgressDialog.show(MainActivity.this, "资源加载中", "资源加载中,请稍后...",false,true);
                break;
            case R.id.btn_two:
                pd1 = new ProgressDialog(mContext);
                //依次设置标题,内容,是否用取消按钮关闭,是否显示进度
                pd1.setTitle("软件更新中");
                pd1.setMessage("软件正在更新中,请稍后...");
                pd1.setCancelable(true);
                //这里是设置进度条的风格,HORIZONTAL是水平进度条,SPINNER是圆形进度条
                pd1.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                pd1.setIndeterminate(true);
                //调用show()方法将ProgressDialog显示出来
                pd1.show();
                break;
            case R.id.btn_three:
                //初始化属性
                progressStart = 0;
                add = 0;
                //依次设置一些属性
                pd2 = new ProgressDialog(MainActivity.this);
                pd2.setMax(MAXVALUE);
                pd2.setTitle("文件读取中");
                pd2.setMessage("文件加载中,请稍后...");
                //这里设置为不可以通过按取消按钮关闭进度条
                pd2.setCancelable(false);
                pd2.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                //这里设置的是是否显示进度,设为false才是显示的哦!
                pd2.setIndeterminate(false);
                pd2.show();
                //这里的话新建一个线程,重写run()方法,
                new Thread()
                {
                    public void run()
                    {
                        while(progressStart < MAXVALUE)
                        {
                            //这里的算法是决定进度条变化的,可以按需要写
                            progressStart = 2 * usetime() ;
                            //把信息码发送给handle让更新界面
                            hand.sendEmptyMessage(123);
                        }
                    }
                }.start();
                break;
        }
    }

    //这里设置一个耗时的方法:
    private int usetime() {
        add++;
        try{
            Thread.sleep(100);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        return add;
    }
}

以上的代码示例基本的样式已经展现,耗时动作还是根据业务需求进行哦~

布局使用

组件需要整合起来,就得需要整体嵌套起来。毕竟“团结就是力量”。

  1. LinearLayout

线性布局,这里最重要的是垂直线性还是水平线性;示例代码如下:

<LinearLayout
        android:id="@+id/ll_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"//重要!!!!!
        android:visibility="gone" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@android:color/holo_purple"
                android:gravity="center_horizontal"
                android:padding="10dp"
                android:text="水平布局" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@android:color/holo_green_light"
                android:gravity="center_horizontal"
                android:padding="10dp"
                android:singleLine="true"
                android:text="水平布局" />
        </LinearLayout>
    </LinearLayout>

在线性布局中有权重layout_weight这个关键的配置。
在线性布局还有一个重要的属性android:layout_weight,这个属性允许我们使用比例的方式来指定控件的大小

例如:在这个的权重比下编辑框和按钮一样宽。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
 
    <EditText
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="编辑框"/>
 
    <Button
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="1"/>
 
 
</LinearLayout>
  1. RelativeLayout

相对布局,这个相对可以对于父布局而言也可以对各个小组件来说。
先post相对父类来说的代码示例;
一般来说alignParentXXX就是对应父组件来说的,这里的XXX指的是方位例如right,left等等。

<RelativeLayout
        android:id="@+id/rl_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/tittle_bg"
        android:padding="10dp"
        android:visibility="gone" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:drawableLeft="@drawable/arrow_pressed"
            android:drawablePadding="5dp"
            android:text="动态" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="好友动态" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:src="@drawable/tittle_add" />
    </RelativeLayout>

相对其他组件而言:layout_toXXXof是关键,同理这里XXX是方位,如rightleft等等

<Button
        android:id="@+id/b3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="3"/>
 
    <Button
        android:id="@+id/b1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/b3"
        android:layout_toLeftOf="@+id/b3"//示例
        android:text="1"/>
 
    <Button
        android:id="@+id/b2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/b3"
        android:layout_toRightOf="@+id/b3"
        android:text="2"/>

在这里要重点区分两个概念:margin针对的是容器中的组件,而padding针对的是组件中的元素,要区分开来!

首先margin代表的是偏移,比如marginleft = "5dp"表示组件离容器左边缘偏移5dp; 而padding代表的则是填充,而填充的对象针对的是组件中的元素,比如TextView中的文字 比如为TextView设置paddingleft = “5dp”,则是在组件里的元素的左边填充5dp的空间!

  1. FrameLayout
    帧布局,这里可以参考菜鸟教程的学习,重点是要知道这个布局的关键在于“帧”。还记得小时候玩的flash动画嘛?就是一帧一帧的。这个布局就体现了这样的“帧”特性。具有覆盖性!根据这样的特性,我特地根据菜鸟里的资源自己构建一个动漫小女孩奔跑Demo
    这一块就不附上代码了,详细的参考Demo代码。

  2. 百分比布局 PercentRelativeLayout…
    百分比布局的出现是为了高效地满足控制组件大小的目的。不过使用的是百分比%进行控制,layout_heightPercent等等?例如:

<?xml version="1.0" encoding="utf-8"?>
<androidx.percentlayout.widget.PercentRelativeLayout

    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView1"
        android:layout_alignParentBottom="true"
        android:gravity="center"
        android:textSize="20sp"
        android:background="#FF1493"
        android:textColor="#ffffff"
        app:layout_widthPercent = "15%"
        app:layout_heightPercent = "100%"
        app:layout_marginPercent="4%"
        android:text="100%"
        />

    <TextView

        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView2"

        android:layout_toRightOf="@+id/textView1"

        android:gravity="center"
        android:textSize="20sp"
        android:background="#FF4081"
        android:textColor="#ffffff"
        app:layout_widthPercent = "15%"
        app:layout_heightPercent = "80%"
        app:layout_marginPercent="4%"
        android:text="80%"/>

    <TextView
        android:id="@+id/textView3"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"


        android:layout_toRightOf="@+id/textView2"

        android:gravity="center"
        android:textSize="20sp"
        android:background="#FF6EB4"
        android:textColor="#ffffff"
        app:layout_widthPercent = "15%"
        app:layout_heightPercent = "60%"
        app:layout_marginPercent="4%"
        android:text="60%"/>

    <TextView

        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView4"

        android:layout_toRightOf="@+id/textView3"

        android:gravity="center"
        android:textSize="20sp"
        android:background=" 	#FFB5C5"
        android:textColor="#ffffff"
        app:layout_widthPercent = "15%"
        app:layout_heightPercent = "40%"
        app:layout_marginPercent="4%"
        android:text="40%"/>


</androidx.percentlayout.widget.PercentRelativeLayout>

自定义控件

在进行自定义控件之前,首先要充分认识布局
根据文档的定义:

布局定义了应用中的界面结构(例如 Activity 的界面结构)。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常用于绘制用户可看到并与之交互的内容。ViewGroup 则是不可见的容器,用于定义 View 和其他 ViewGroup 对象的布局结构。

  1. 布局引入
    关键的xml语句是<include layout =''>这里可以参考我自己写的一个Demo,主要就是更换一个标题栏。
 		//隐藏原标题栏,这段代码是在mainActivity中展现
        ActionBar actionBar = getSupportActionBar();
        if(actionBar != null){
            actionBar.hide();
        }

通过继承实现复用,多态

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.title,this);
    }
}

但是以上这个代码会导致报错,没办法加载出正确的TitleLayout。修改代码如下;

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.title,this);
    }
	//这个构造方法才是最重要的!!!之前少了一个参数就出错了,至于这个的原因,之后看看源码好好了解一下
    public TitleLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title,this);
    }
}

ListView

这个虽然已经不如RecyclerView主流,但是还是要熟悉一下。明白来路更好地向前。在《第一行代码》中直接给的标题就是最常用和最难用的控件,虽然现在回过头看有点言过其实,但是那个时代的确如此!附上主要的逻辑代码:

public class MainActivity extends AppCompatActivity {
    ListView listView;
    ArrayList<String> data = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        createData();
        listView = findViewById(R.id.listView);
//重点是使用适配器进行适配的
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,data);
        listView.setAdapter(arrayAdapter);
    }

    private void createData() {
        for(int i = 0; i < 100; i++){
            data.add(String.valueOf("num is "+i));
        }
    }
}

回顾上面的知识点,你也可以自己构建一个item的布局。具体的实现逻辑可以参考我自建的简单Demo

当熟悉一个新的组件的时候后,需要考虑如何提高其性能:通过缓存在实际中可以提高运行效率。不过现在的cpu已经很强大,这些性能问题也许就不像之前那么必不可少。主要是实现功能。以下的代码中view.getTagview.setTag这两个需要回顾一下view的方法文档。本段代码可以实现高效运行ListView。

 @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Animal animal = (Animal) getItem(position);
        ViewHolder viewHolder = new ViewHolder();
        View view;
        if(convertView == null){
            view = LayoutInflater.from(getContext()).inflate(animalResourceId,parent,false);//这个代码很常用,需要认真看看源码,最后的boolean有什么用。
            viewHolder.imageView = view.findViewById(R.id.imageView);
            viewHolder.textView = view.findViewById(R.id.textView);
            view.setTag(viewHolder);//view中储存该控件的组件
        }else{
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();//获取控件
        }
        viewHolder.imageView.setImageResource(animal.getPicID());
        viewHolder.textView.setText(animal.getName());
        return view;
    }
    //使用一个内部类,这样里面的组件直接就示例
    class  ViewHolder{
        ImageView imageView ;
        TextView  textView ;
    }

item搞定,那么也得设计一些监听事件,让整个listview活过来。
AdapterView.OnItemClickListener是监听方法。

 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getApplicationContext(),"position:"+position,Toast.LENGTH_SHORT).show();
            }
        });

RecyclerView

recyclerView几乎具有List View的全部“遗产”,比ListView更高级!Google的官方文档都推荐使用Recycler View,得到“爸爸”的鼎力支持还能不用吗?

确定布局后,您需要实现 Adapter 和 ViewHolder。这两个类配合使用,共同定义数据的显示方式。ViewHolder 是包含列表中各列表项的布局的 View 的封装容器。Adapter 会根据需要创建 ViewHolder 对象,还会为这些视图设置数据。将视图与其数据相关联的过程称为“绑定”。

布局的样式可以:

RecyclerView 中的列表项由 LayoutManager 类负责排列。RecyclerView 库提供了三种布局管理器,用于处理最常见的布局情况:

LinearLayoutManager 将各个项排列在一维列表中。
GridLayoutManager 将所有项排列在二维网格中:

如果网格垂直排列,GridLayoutManager 会尽量使每行中所有元素的宽度和高度相同,但不同的行可以有不同的高度。
如果网格水平排列,GridLayoutManager 会尽量使每列中所有元素的宽度和高度相同,但不同的列可以有不同的宽度。

StaggeredGridLayoutManager 与 GridLayoutManager 类似,但不要求同一行中的列表项具有相同的高度(垂直网格有此要求)或同一列中的列表项具有相同的宽度(水平网格有此要求)。其结果是,同一行或同一列中的列表项可能会错落不齐。
核心的代码如下:详细的内容可以参考Demo,注意该Demo中是含有ListView和RecyclerView。

 AnimalRecyclerAdapter animalAdapter = new AnimalRecyclerAdapter(animals);//animals是自己配的数据,根据业务需求自己配
        GridLayoutManager gridLayoutManager = new GridLayoutManager(this,4);
        recyclerView.setAdapter(animalAdapter);
        recyclerView.setLayoutManager(gridLayoutManager);

点九图 nine patch

何为点九图?

点九图又称九图,是一种png格式的图片,其后缀为.9.png,其与传统png图片不同的地方是,点九图的四周边缘各>有1个像素宽高的区域,而且只能填充两种颜色,透明(#00000000)和黑色(#FF000000),其目的是用于对该图片的扩展区域和内容显示区域进行定义。使用点九PNG技术,可以将图片横向和纵向同时进行拉伸,并能保持图片细节,不会因为图片拉伸而模糊失真。

了解之后,可以参考我自己写的Demo进行修改。该Demo是最常用的仿微信的聊天框ui设计。其中的代码可以再自己update一下。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-27 11:58:42  更:2021-08-27 11:59:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:40:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码