android表白app

一、前言

  马上就要520和521了,是不是还有像我一样的单身狗啊。我就知道有,所以这两天简单写了这个小程序(其实是替别人写的),虽然我并不会用去骗女孩子(因为最近太忙了,实习完之后要搞毕设,要搞论文啊,谁能帮帮我...),但是我想很多人肯定会感兴趣吧。如果你感兴趣就拿去逗妹子一乐吧。

  如果你很感兴趣,你可以在我写的基础上增辉加彩,或者根据我提供的资源自己动手,尝试一下。

二、先show一下效果

  

三、Android手机如何录制屏幕及转GIF

  https://www.aswifter.com/2015/07/10/android-record-video-to-gif/

  

  第一次试的时候没有成功,第二次设定屏幕分辨率后成功了,但是效果太差。果断又试了第三次,成功了,手机根目录出现了刚刚录制的视屏文件。

  adb pull 会把文件从手机上复制到本地(ANDROID_SDK_HOME/platform-tools目录下,也就是adb.exe所在的目录)

  接着就是转换成gif了,这里我用PS处理

  

    

   然后文件——》存储为web所有格式——》选择gif。如果gif过大,可能会导致ps崩溃,简单的做法就是调整图片的大小,就可以了。

四、下载地址

  apk文件:https://github.com/hjzgg/LoveDemo/tree/master/bin

  项目:https://github.com/hjzgg/LoveDemo

五、技术路线,分享我的制作过程

1.准备

  大二的时候搞过一段时间的android,时隔一年半,好多东西都忘了,不过现在捡起来也不晚。

  开发工具使用eclipse或者android studio。我使用的eclipse,那么就要自己去安装ADT和SDK了,安装的时间有点蛋疼啊。

2.资源收集

  作为一个表白程序,必须要有图片吧,文字吧, 最好加上背景音乐吧,不然就真的没有意思了。下面分享几个资源链接:

  文字特效: https://github.com/elevenetc/TextSurface

  图片切花特效: https://github.com/daimajia/AndroidImageSlider

  音乐播放器: http://www.cnblogs.com/TerryBlog/archive/2010/06/26/1765910.html

  

  先说一下文字特效,将文字特效的代码下载下来后,所有的演示代码放在了\app\src\main\java\su\levenetc\android\textsurface\sample\checks这里面,app\src\main\java\su\levenetc\android\textsurface\sample\SampleActivity.java是app入口activity。最主要的代码放在了library目录下,需要将library\src\main下面的文件复制到我们的项目中,参考入口activity的内容进行调用就可以了。 资源中提供了很多文字展示的效果,本人愚钝,只用了两个,而且用的不是太好。我主要增加了文字处理,效果结合的功能。将要展示的文字按照4句划分,然后调用文字效果展示。文字资源放在了assets文件夹下面。

  图片切换特效很好用,进本不要改动,直接把图片换了就行了,效果不错。

  音乐播放器引用网上的一位哥们儿的,写的简介靠谱,这里直接拿来用了,用的是MediaPlayer进行音乐播放。我改了一些地方,里面有点儿小bug。增加了一个功能,就是在sd卡不存在的时候(无论是内置的还是外置的),依然可以获取到音乐文件,考虑了好多方式,比如直接调用网上的,或者调用手机内存中的...,想了想还是将音乐文件放在项目当中了,可以放在res/raw下,也可以放在assets下,各有好处,本人放在了res/raw目录下。还有一个要注意的是判断手机的sd卡环境是否可以使用。具体的还是看代码吧。

3.主要代码

  说了这么多,最主要的代码都是在一个activity中,代码如下:

  MainActivity.java

public class MainActivity extends ListActivity implements BaseSliderView.OnSliderClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化图片切换
        initChangePicture();
        //初始化音乐
        initMusic();
        //初始化文字展示
        initWord();
    }

    @Override
    public void onSliderClick(BaseSliderView slider) {
        Toast.makeText(this, slider.getBundle().get("extra") + "",Toast.LENGTH_SHORT).show();
    }

    private SliderLayout mDemoSlider;
    private void initChangePicture(){
         mDemoSlider = (SliderLayout)findViewById(R.id.slider);

         //两种方式加载数据

         //加载本地
         HashMap<String,String> url_maps = new HashMap<String, String>();
         url_maps.put("GitOnWay", "http://gitonway.blog.163.com/");

         //加载网络
         HashMap<String,Integer> file_maps = new HashMap<String, Integer>();
         file_maps.put("love-A",R.drawable.a);
         file_maps.put("love-B",R.drawable.b);
         file_maps.put("love-C",R.drawable.c);
         file_maps.put("love-D", R.drawable.d);

         for(String name : file_maps.keySet()){
             TextSliderView textSliderView = new TextSliderView(this);
             // 初始化幻灯片页面
             textSliderView
                     .description(name)
                     .image(file_maps.get(name))
                     .setOnSliderClickListener(this);

             //添加要传递的数据
             textSliderView.getBundle()
                     .putString("extra",name);

            mDemoSlider.addSlider(textSliderView);
         }

//       幻灯片切换方式
         mDemoSlider.setPresetTransformer(SliderLayout.Transformer.Accordion);
//       指示符位置
         mDemoSlider.setPresetIndicator(SliderLayout.PresetIndicators.Center_Bottom);
//       定义指示器样式
//       mDemoSlider.setCustomIndicator(your view);
//       幻灯片循环
//       mDemoSlider.startAutoCycle();
//       停止循环
         mDemoSlider.stopAutoCycle();
//       设置指示器的显示与否
         mDemoSlider.setIndicatorVisibility(PagerIndicator.IndicatorVisibility.Visible);
//       设置幻灯片的转化时间
//       mDemoSlider.setSliderTransformDuration(5000, null);
//       用来自定义幻灯片标题的显示方式
         mDemoSlider.setCustomAnimation(new DescriptionAnimation());
//       幻灯片切换时间
         mDemoSlider.setDuration(3000);

//         实现随机切换
         TimerTask task = new TimerTask() {
             @Override
             public void run() {
                 Transformer[] tranformers = SliderLayout.Transformer.values();
                 Transformer transformer = tranformers[(int) (Math.random() * tranformers.length)];
                 mDemoSlider.setPresetTransformer(transformer);
             }
         };

         new Timer().schedule(task, 2000, 2000);
    }

    //res/raw中的音乐文件资源映射
    private Map<String, Integer> musicPath;
    //播放对象
      private MediaPlayer myMediaPlayer;
      //播放列表
      private List<String> myMusicList = new ArrayList<String>();
      //当前播放歌曲的索引
      private int currentListItem=0;
      //音乐的路径, 如果存在sd卡,则使用sd卡,否则使用内存中的data目录
      private static String MUSIC_PATH = hasSDCardMounted() ?  new String(Environment.getExternalStorageDirectory().getAbsolutePath() + "/hjz/")
                  : null;

    private void initMusic(){
        myMediaPlayer=new MediaPlayer();
        findView();
        musicList();
        listener();

        //自动播放第一首歌
        if(myMusicList.size() > 0){
            playMusic(MUSIC_PATH, myMusicList.get(currentListItem));
        }
    }

    public static boolean hasSDCardMounted() {
        String state = Environment.getExternalStorageState();
        if (state != null && state.equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }

    //绑定音乐
    private void musicList(){
        try {
            File home = new File(MUSIC_PATH);
            //如果有sd卡,但是sd卡中没有指定的音乐文件夹,则采用项目中的音乐文件
            if(MUSIC_PATH == null || home.listFiles() == null) {//绑定 res/raw下的音乐文件
                MUSIC_PATH = null;
                musicPath = new HashMap<String, Integer>();
                musicPath.put("杨宗纬 - 一次就好.mp3", R.raw.yi_ci_jiu_hao);
                musicPath.put("霍建华,赵丽颖 - 不可说.mp3", R.raw.bu_ke_shuo);
                musicPath.put("川井憲次 - 孤独な巡礼.mp3", R.raw.gu_du_xun_li);
                myMusicList.addAll(musicPath.keySet());
            } else {
                Log.v("MUSIC_PATH", MUSIC_PATH);
                if(home.listFiles(new MusicFilter()).length>0){
                    for(File file:home.listFiles(new MusicFilter())){
                        myMusicList.add(file.getName());
                    }
                }
            }
            if(myMusicList.size() > 0) {
                ArrayAdapter<String> musicList = new ArrayAdapter<String>(MainActivity.this, R.layout.musicitme, myMusicList);
                setListAdapter(musicList);
            }
        } catch (Exception e) {
            Log.e("获取音乐文件出错:", e.toString());
        }
    }

    //获取按钮
   void findView(){
       viewHolder.start=(Button)findViewById(R.id.start);
       viewHolder.stop=(Button)findViewById(R.id.stop);
       viewHolder.next=(Button)findViewById(R.id.next);
       viewHolder.pause=(Button)findViewById(R.id.pause);
       viewHolder.last=(Button)findViewById(R.id.last);
   }

   //监听事件
   void listener(){
       //停止
       viewHolder.stop.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if(myMediaPlayer.isPlaying()){
                myMediaPlayer.reset();
            }
        }
    });
       //开始
     viewHolder.start.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            if(myMusicList.size() == 0) return;
            playMusic(MUSIC_PATH, myMusicList.get(currentListItem));
        }
    });
       //下一首
       viewHolder.next.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            nextMusic();
        }
    });
       //暂停
       viewHolder.pause.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            if(myMusicList.size() == 0) return;
            if(myMediaPlayer.isPlaying()){
                myMediaPlayer.pause();
            }else{
                myMediaPlayer.start();
            }
        }
    });
       //上一首
    viewHolder.last.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            lastMusic();
        }
    });

   }

   //播放音乐
   void playMusic(String basePath, String path){
      try {
           if(basePath != null) {
               myMediaPlayer.reset();
               myMediaPlayer.setDataSource(basePath+path);
               myMediaPlayer.prepare();
           } else {
               myMediaPlayer.pause();
               myMediaPlayer.release();
               myMediaPlayer = MediaPlayer.create(MainActivity.this, musicPath.get(path));
           }
           myMediaPlayer.start();
           myMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    nextMusic();
                }
            });
       } catch (Exception e) {
           Log.e("播放sd卡音乐失败", e.toString());
           e.printStackTrace();
       }
   }

   //下一首
   void nextMusic(){
       if(myMusicList.size() > 0) {
           if(++currentListItem>=myMusicList.size()){
               currentListItem=0;
           }
           playMusic(MUSIC_PATH, myMusicList.get(currentListItem));
       }
   }

   //上一首
   void lastMusic(){
       if(myMusicList.size() > 0) {
           if(currentListItem!=0) {
               playMusic(MUSIC_PATH, myMusicList.get(--currentListItem));
            }  else{
               playMusic(MUSIC_PATH, myMusicList.get(currentListItem=myMusicList.size()-1));
            }
       }
   }

   //当用户返回时结束音乐并释放音乐对象
       @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
           if(keyCode==KeyEvent.KEYCODE_BACK){
               myMediaPlayer.stop();
               myMediaPlayer.release();
               this.finish();
               return true;
           }
        return super.onKeyDown(keyCode, event);
    }

    //当选择列表项时播放音乐
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        currentListItem=position;
        playMusic(MUSIC_PATH, myMusicList.get(currentListItem));
    }

    //初始化文字展示
    private TextSurface textSurface;
    private void initWord(){
        LinearLayout layout = (LinearLayout) findViewById(R.id.LinearLayoutWord);//找到你要设透明背景的layout 的id
        layout.getBackground().setAlpha(60);//0~255透明度值
        textSurface = (TextSurface) findViewById(R.id.text_surface);
        textSurface.postDelayed(new Runnable() {
            @Override public void run() {
                show();
            }
        }, 1000);
    }

    private void show() {
        textSurface.reset();
        List<AnimationsSet> animationsSets = new ArrayList<AnimationsSet>();
        animationsSets.add(CookieThumperSample.getCookieThumperAnimations(getAssets()));
        animationsSets.addAll(SlideSample.getSlideAnimations(getContents()));
        textSurface.play(TYPE.SEQUENTIAL, animationsSets.toArray(new AnimationsSet[]{}));

//        ColorSample.play(textSurface);
//        AlignSample.play(textSurface);
//        Rotation3DSample.play(textSurface);
//        ScaleTextSample.run(textSurface);
//        ShapeRevealLoopSample.play(textSurface);
//        ShapeRevealSample.play(textSurface);
//        SlideSample.play(textSurface);
//        SurfaceScaleSample.play(textSurface);
//        SurfaceTransSample.play(textSurface);
    }

    private List<String> getContents(){
        List<String> contents = new ArrayList<String>();
        try{
           //得到资源中的asset数据流
           String fileName = "content.txt"; //文件名字
           String res="";
           InputStream in = getResources().getAssets().open(fileName);
           int length = in.available();
           byte [] buffer = new byte[length];
           in.read(buffer);
           in.close();
           res = EncodingUtils.getString(buffer, "UTF-8");
           String[] strings = res.split("[,|,|\\.|。]");
           int len = strings.length/4 * 4;
           for(int i=0; i < len; ++i)
               contents.add(strings[i]);
        }catch(Exception e){
          e.printStackTrace();
          Log.e("getContents", e.toString());
       }
        return contents;
    }
}

  activity_main.xml(页面布局)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.gitonway.androidimagesliderdemo.activity.MainActivity">

    <LinearLayout android:id="@+id/LinearLayoutPicture"
        android:orientation="vertical"
        android:layout_weight="3"
        android:layout_height="fill_parent"
        android:layout_width="match_parent">
        <!-- 图片切换  -->
        <com.gitonway.androidimagesliderdemo.widget.imageslider.SliderLayout
            android:id="@+id/slider"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            custom:pager_animation="Accordion"
            custom:auto_cycle="true"
            custom:indicator_visibility="visible"
            custom:pager_animation_span="1100"/>

      <!--  <com.gitonway.androidimagesliderdemo.widget.imageslider.Indicators.PagerIndicator
            android:id="@+id/custom_indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            custom:selected_color="#0095BF"
            custom:unselected_color="#55333333"
            custom:selected_drawable="@drawable/ic_launcher"
            custom:shape="oval"
            custom:selected_padding_left="6dp"
            custom:selected_padding_right="6dp"
            custom:unselected_padding_left="2dp"
            custom:unselected_padding_right="2dp"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            custom:selected_width="6dp"
            custom:selected_height="6dp"
            custom:unselected_width="6dp"
            custom:unselected_height="6dp"
            android:layout_marginBottom="20dp"
            />
        <com.gitonway.androidimagesliderdemo.widget.imageslider.Indicators.PagerIndicator
            android:id="@+id/custom_indicator2"
            style="@style/AndroidImageSlider_Corner_Oval_Orange"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="20dp"
            />  -->
    </LinearLayout>

    <!-- 文字展现  -->
    <LinearLayout android:id="@+id/LinearLayoutWord"
        android:layout_weight="3"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:background="@android:color/background_dark"
        android:layout_width="match_parent">

        <com.textsurface.TextSurface
            android:id="@+id/text_surface"
            android:layout_height="fill_parent"
            android:layout_width="match_parent"/>

    </LinearLayout>

    <!-- 音乐播放器  -->

    <LinearLayout
        android:id="@+id/LinearLayoutMusic"
        android:layout_width="match_parent"
        android:layout_weight="4"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <ListView
            android:id="@id/android:list"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="fill_parent"
            android:scrollbars="vertical" />

        <LinearLayout
            android:id="@+id/bottomBtn"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center|center_horizontal|center_vertical"
            android:orientation="horizontal" >

            <Button   android:id="@+id/last"
              android:background="@drawable/last"
              android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

            <Button  android:id="@+id/stop"
              android:background="@drawable/stop"
              android:layout_marginLeft="10dp"
              android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

            <Button  android:id="@+id/start"
              android:background="@drawable/start"
              android:layout_marginLeft="10dp"
              android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

            <Button  android:id="@+id/pause" android:layout_width="wrap_content"
              android:background="@drawable/pause"
              android:layout_marginLeft="10dp"
              android:layout_height="wrap_content"></Button>

            <Button  android:id="@+id/next"
              android:background="@drawable/next"
              android:layout_marginLeft="10dp"
              android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

  

时间: 2024-10-24 12:21:27

android表白app的相关文章

Android Tv app 与 mobile app 界面呈现的区别

公司的一个项目是android tv的谢了片日报总结:android tv app呈现ui 与手机app的区别 android tv  app和 mobile app 的主要区别在表现形式上 1.焦点移动的处理 从代码上可以明显看出到处都有对焦点获取的处理,这是mobile app所不需要的. 触摸屏与遥控的不同操作方式决定了:tv遥控操作方式在屏幕上是先获取焦点(遥控决定焦点移动)再获取点击,而mobile触摸方式是直接的点击获取与焦点获取一起通常只需要处理点击获取 2.布局边界处理 遥控操作

[Android Memory] App调试内存泄露之Context篇(上)

转载自:http://www.cnblogs.com/qianxudetianxia/p/3645106.html Context作为最基本的上下文,承载着Activity,Service等最基本组件.当有对象引用到Activity,并不能被回收释放,必将造成大范围的对象无法被回收释放,进而造成内存泄漏. 下面针对一些常用场景逐一分析. 1. CallBack对象的引用 先看一段代码: @Override protectedvoid onCreate(Bundle state){ super.o

[Android Memory] App调试内存泄露之Context篇(下)

转载地址:http://www.cnblogs.com/qianxudetianxia/p/3655475.html 5. AsyncTask对象 我N年前去盛大面过一次试,当时面试官极力推荐我使用AsyncTask等系统自带类去做事情,当然无可厚非. 但是AsyncTask确实需要额外注意一下.它的泄露原理和前面Handler,Thread泄露的原理差不多,它的生命周期和Activity不一定一致. 解决方案是:在activity退出的时候,终止AsyncTask中的后台任务. 但是,问题是如

【Android端 APP GPU过度绘制】GPU过度绘制及优化

一.Android端的卡顿 Android端APP在具体使用的过程中容易出现卡顿的情况,比如查看页面时出现一顿一顿的感受,切换tab之后响应很慢,或者具体滑动操作的时候也很慢. 二.卡顿的原因 卡顿的原因可能有很多种,比如: 1.CPU过高 2.内存溢出 3.主线程处理IO操作等 - 其中过度绘制,是一个容易被忽视但也最好修改并且能够看到效果的内容,其中Android官网给出的过度绘制相关内容见:https://developer.android.com/topic/performance/re

抓包工具Fidder详解(主要来抓取Android中app的请求)

抓包工具Fidder详解(主要来抓取Android中app的请求) 今天闲着没吊事,来写一篇关于怎么抓取Android中的app数据包?工欲行其事,必先利其器,上网google了一下,发现了一款神器:Fiddler,这个貌似是所有软件开发者必备神器呀!这款工具不仅可以抓取PC上开发web时候的数据包,而且可以抓取移动端(Android,Iphone,WindowPhone等都可以),太强大了,以前搞web的时候,知道有一款叫做HttpWatch工具,可以抓取web的请求数据包的,但是和这款神器来

React-Native 开发 android & ios App,共享一份代码

React-Native 开发的App, 所有组件ios & android 共用, 共享一份代码 包括一些自定义的组件, 如NavigationBar, TabBar, SegmentedControl, 使用字体图标, 具有一定的参考意义 主要专注于布局, 共享组件/代码, 以及一些React自带的组件, 如: ScrollView, TouchableOpacity, View, Text, ListView, Image, WebView 和 Api的使用, 这并不是一个完整版, 只是业

Android Wear - App Structure for Android Wear(应用结构)

原文地址:http://developer.android.com/design/wear/structure.html 用户习惯于点击图标来启动应用程序,但是Android Wear不一样.一个典型的Wear应用程序会在一个情境的合适时刻插入一张卡片到信息流中.这张卡片可能会包含一个用于快速交互的按钮来打开一个全屏视图(在一些情况下,卡片也可能不会提供交互按钮): 以下是简单排序的构建模块.你可以使用其中的一个或者多个模块,但是我们强烈推荐不要构建这样的应用:用户在启动或者退出应用之前必须仔细

Android之App应用启动分析与优化

前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动      当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动.冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量.布局.绘制),最后显示在界面上. 2.)热启动      当启动

Android开发App工程结构搭建

本文算是一篇漫谈,谈一谈关于android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构.      关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角度,看到整齐的代码,优美的分层总是一种舒服的享受的.      从艺术的角度看,其实我们是在追求一种美. 本文先分析几个当今比较流行的android软件包,最后我们汲取其中觉得优秀的部分,搭建我们自己的通用android工程模板.      1. 微盘      2. 久忆日记      3.网易新